home *** CD-ROM | disk | FTP | other *** search
/ Aminet 48 / Aminet 48 (2002)(GTI - Schatztruhe)[!][Apr 2002].iso / Aminet / text / edit / vim60src.lha / Vim / vim60 / src / gui.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-25  |  96.4 KB  |  4,076 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *                GUI/Motif support by Robert Webb
  5.  *
  6.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  7.  * Do ":help credits" in Vim to see a list of people who contributed.
  8.  * See README.txt for an overview of the Vim source code.
  9.  */
  10.  
  11. #include "vim.h"
  12.  
  13. /* Structure containing all the GUI information */
  14. gui_T gui;
  15.  
  16. #ifdef FEAT_MBYTE
  17. static void set_guifontwide __ARGS((char_u *font_name));
  18. #endif
  19. static void gui_check_pos __ARGS((void));
  20. static void gui_position_components __ARGS((int));
  21. static void gui_outstr __ARGS((char_u *, int));
  22. static void gui_screenchar __ARGS((int off, int flags, guicolor_T fg, guicolor_T bg, int back));
  23. static void gui_delete_lines __ARGS((int row, int count));
  24. static void gui_insert_lines __ARGS((int row, int count));
  25. static void gui_do_scrollbar __ARGS((win_T *wp, int which, int enable));
  26. static void gui_update_horiz_scrollbar __ARGS((int));
  27. static win_T *xy2win __ARGS((int x, int y));
  28.  
  29. static int can_update_cursor = TRUE; /* can display the cursor */
  30.  
  31. /*
  32.  * The Athena scrollbars can move the thumb to after the end of the scrollbar,
  33.  * this makes the thumb indicate the part of the text that is shown.  Motif
  34.  * can't do this.
  35.  */
  36. #if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_MAC)
  37. # define SCROLL_PAST_END
  38. #endif
  39.  
  40. /*
  41.  * gui_start -- Called when user wants to start the GUI.
  42.  *
  43.  * Careful: This function can be called recursively when there is a ":gui"
  44.  * command in the .gvimrc file.  Only the first call should fork, not the
  45.  * recursive call.
  46.  */
  47.     void
  48. gui_start()
  49. {
  50.     char_u    *old_term;
  51. #if defined(UNIX) && !defined(__BEOS__)
  52.     pid_t    pid = -1;
  53.     int        dofork = TRUE;
  54. #endif
  55.     static int    recursive = 0;
  56.  
  57.     old_term = vim_strsave(T_NAME);
  58.  
  59.     /*
  60.      * Set_termname() will call gui_init() to start the GUI.
  61.      * Set the "starting" flag, to indicate that the GUI will start.
  62.      *
  63.      * We don't want to open the GUI shell until after we've read .gvimrc,
  64.      * otherwise we don't know what font we will use, and hence we don't know
  65.      * what size the shell should be.  So if there are errors in the .gvimrc
  66.      * file, they will have to go to the terminal: Set full_screen to FALSE.
  67.      * full_screen will be set to TRUE again by a successful termcapinit().
  68.      */
  69.     settmode(TMODE_COOK);        /* stop RAW mode */
  70.     if (full_screen)
  71.     cursor_on();            /* needed for ":gui" in .vimrc */
  72.     gui.starting = TRUE;
  73.     full_screen = FALSE;
  74.  
  75. #if defined(UNIX) && !defined(__BEOS__)
  76.     if (!gui.dofork || vim_strchr(p_go, GO_FORG) || recursive)
  77.     dofork = FALSE;
  78. #endif
  79.     ++recursive;
  80.  
  81.     termcapinit((char_u *)"builtin_gui");
  82.     gui.starting = recursive - 1;
  83.  
  84.     if (!gui.in_use)            /* failed to start GUI */
  85.     {
  86.     termcapinit(old_term);        /* back to old term settings */
  87.     settmode(TMODE_RAW);        /* restart RAW mode */
  88. #ifdef FEAT_TITLE
  89.     set_title_defaults();        /* set 'title' and 'icon' again */
  90. #endif
  91.     }
  92.  
  93.     vim_free(old_term);
  94.  
  95. #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11)
  96.     if (gui.in_use)
  97.     /* Display error messages in a dialog now. */
  98.     display_errors();
  99. #endif
  100.  
  101. #if defined(UNIX) && !defined(__BEOS__) && !defined(__QNXNTO__)
  102.     /*
  103.      * Quit the current process and continue in the child.
  104.      * Makes "gvim file" disconnect from the shell it was started in.
  105.      * Don't do this when Vim was started with "-f" or the 'f' flag is present
  106.      * in 'guioptions'.
  107.      */
  108.     if (gui.in_use && dofork)
  109.     {
  110.     pid = fork();
  111.     if (pid > 0)        /* Parent */
  112.     {
  113.         /* Give the child some time to do the setsid(), otherwise the
  114.          * exit() may kill the child too (when starting gvim from inside a
  115.          * gvim). */
  116.         ui_delay(100L, TRUE);
  117.  
  118.         /*
  119.          * The parent must skip the normal exit() processing, the child
  120.          * will do it.  For example, GTK messes up signals when exiting.
  121.          */
  122.         _exit(0);
  123.     }
  124.  
  125. # if defined(HAVE_SETSID) || defined(HAVE_SETPGID)
  126.     /*
  127.      * Change our process group.  On some systems/shells a CTRL-C in the
  128.      * shell where Vim was started would otherwise kill gvim!
  129.      */
  130.     if (pid == 0)        /* child */
  131. #  if defined(HAVE_SETSID)
  132.         (void)setsid();
  133. #  else
  134.         (void)setpgid(0, 0);
  135. #  endif
  136. # endif
  137.     }
  138. #else
  139. # if defined(__QNXNTO__)
  140.     if (gui.in_use && dofork)
  141.     procmgr_daemon(0, PROCMGR_DAEMON_KEEPUMASK | PROCMGR_DAEMON_NOCHDIR |
  142.         PROCMGR_DAEMON_NOCLOSE | PROCMGR_DAEMON_NODEVNULL);
  143. # endif
  144. #endif
  145.  
  146. #ifdef FEAT_AUTOCMD
  147.     /* If the GUI started successfully, trigger the GUIEnter event */
  148.     if (gui.in_use)
  149.     apply_autocmds(EVENT_GUIENTER, NULL, NULL, FALSE, curbuf);
  150. #endif
  151.     --recursive;
  152. }
  153.  
  154. /*
  155.  * Call this when vim starts up, whether or not the GUI is started
  156.  */
  157.     void
  158. gui_prepare(argc, argv)
  159.     int        *argc;
  160.     char    **argv;
  161. {
  162.     gui.in_use = FALSE;            /* No GUI yet (maybe later) */
  163.     gui.starting = FALSE;        /* No GUI yet (maybe later) */
  164.     gui_mch_prepare(argc, argv);
  165. }
  166.  
  167. /*
  168.  * Try initializing the GUI and check if it can be started.
  169.  * Used from main() to check early if "vim -g" can start the GUI.
  170.  * Used from gui_init() to prepare for starting the GUI.
  171.  * Returns FAIL or OK.
  172.  */
  173.     int
  174. gui_init_check()
  175. {
  176.     static int result = MAYBE;
  177.  
  178.     if (result != MAYBE)
  179.     {
  180.     if (result == FAIL)
  181.         EMSG(_("E229: Cannot start the GUI"));
  182.     return result;
  183.     }
  184.  
  185.     gui.shell_created = FALSE;
  186.     gui.dying = FALSE;
  187.     gui.in_focus = TRUE;        /* so the guicursor setting works */
  188.     gui.dragged_sb = SBAR_NONE;
  189.     gui.dragged_wp = NULL;
  190.     gui.pointer_hidden = FALSE;
  191.     gui.col = 0;
  192.     gui.row = 0;
  193.     gui.num_cols = Columns;
  194.     gui.num_rows = Rows;
  195.  
  196.     gui.cursor_is_valid = FALSE;
  197.     gui.scroll_region_top = 0;
  198.     gui.scroll_region_bot = Rows - 1;
  199.     gui.scroll_region_left = 0;
  200.     gui.scroll_region_right = Columns - 1;
  201.     gui.highlight_mask = HL_NORMAL;
  202.     gui.char_width = 1;
  203.     gui.char_height = 1;
  204.     gui.char_ascent = 0;
  205.     gui.border_width = 0;
  206.  
  207.     gui.norm_font = NOFONT;
  208.     gui.bold_font = NOFONT;
  209.     gui.ital_font = NOFONT;
  210.     gui.boldital_font = NOFONT;
  211. #ifdef FEAT_XFONTSET
  212.     gui.fontset = NOFONTSET;
  213. #endif
  214.  
  215. #ifdef FEAT_MENU
  216. # ifdef FONTSET_ALWAYS
  217.     gui.menu_fontset = NOFONTSET;
  218. # else
  219.     gui.menu_font = NOFONT;
  220. # endif
  221.     gui.menu_is_active = TRUE;        /* default: include menu */
  222. # ifndef FEAT_GUI_GTK
  223.     gui.menu_height = MENU_DEFAULT_HEIGHT;
  224.     gui.menu_width = 0;
  225. # endif
  226. #endif
  227. #if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
  228.     gui.toolbar_height = 0;
  229. #endif
  230. #if defined(FEAT_FOOTER) && defined(FEAT_GUI_MOTIF)
  231.     gui.footer_height = 0;
  232. #endif
  233. #ifdef FEAT_BEVAL
  234.     gui.tooltip_fontset = NOFONTSET;
  235. #endif
  236.  
  237.     gui.scrollbar_width = gui.scrollbar_height = SB_DEFAULT_WIDTH;
  238.     gui.prev_wrap = -1;
  239.  
  240. #ifdef ALWAYS_USE_GUI
  241.     result = OK;
  242. #else
  243.     result = gui_mch_init_check();
  244. #endif
  245.     return result;
  246. }
  247.  
  248. /*
  249.  * This is the call which starts the GUI.
  250.  */
  251.     void
  252. gui_init()
  253. {
  254.     win_T    *wp;
  255.     static int    recursive = 0;
  256.  
  257.     /*
  258.      * It's possible to use ":gui" in a .gvimrc file.  The first halve of this
  259.      * function will then be executed at the first call, the rest by the
  260.      * recursive call.  This allow the shell to be opened halfway reading a
  261.      * gvimrc file.
  262.      */
  263.     if (!recursive)
  264.     {
  265.     ++recursive;
  266.  
  267.     clip_init(TRUE);
  268.  
  269.     /* If can't initialize, don't try doing the rest */
  270.     if (gui_init_check() == FAIL)
  271.     {
  272.         --recursive;
  273.         clip_init(FALSE);
  274.         return;
  275.     }
  276.  
  277.     /*
  278.      * Set up system-wide default menus.
  279.      */
  280. #if defined(SYS_MENU_FILE) && defined(FEAT_MENU)
  281.     if (vim_strchr(p_go, GO_NOSYSMENU) == NULL)
  282.     {
  283.         sys_menu = TRUE;
  284.         do_source((char_u *)SYS_MENU_FILE, FALSE, FALSE);
  285.         sys_menu = FALSE;
  286.     }
  287. #endif
  288.  
  289.     /*
  290.      * Switch on the mouse by default, unless the user changed it already.
  291.      * This can then be changed in the .gvimrc.
  292.      */
  293.     if (!option_was_set((char_u *)"mouse"))
  294.         set_string_option_direct((char_u *)"mouse", -1,
  295.                              (char_u *)"a", OPT_FREE);
  296.  
  297.     /*
  298.      * If -U option given, use only the initializations from that file and
  299.      * nothing else.  Skip all initializations for "-U NONE" or "-u NORC".
  300.      */
  301.     if (use_gvimrc != NULL)
  302.     {
  303.         if (STRCMP(use_gvimrc, "NONE") != 0
  304.             && STRCMP(use_gvimrc, "NORC") != 0
  305.             && do_source(use_gvimrc, FALSE, FALSE) != OK)
  306.         EMSG2(_("E230: Cannot read from \"%s\""), use_gvimrc);
  307.     }
  308.     else
  309.     {
  310.         /*
  311.          * Get system wide defaults for gvim, only when file name defined.
  312.          */
  313. #ifdef SYS_GVIMRC_FILE
  314.         do_source((char_u *)SYS_GVIMRC_FILE, FALSE, FALSE);
  315. #endif
  316.  
  317.         /*
  318.          * Try to read GUI initialization commands from the following
  319.          * places:
  320.          * - environment variable GVIMINIT
  321.          * - the user gvimrc file (~/.gvimrc)
  322.          * - the second user gvimrc file ($VIM/.gvimrc for Dos)
  323.          * - the third user gvimrc file ($VIM/.gvimrc for Amiga)
  324.          * The first that exists is used, the rest is ignored.
  325.          */
  326.         if (process_env((char_u *)"GVIMINIT", FALSE) == FAIL
  327.          && do_source((char_u *)USR_GVIMRC_FILE, TRUE, FALSE) == FAIL
  328. #ifdef USR_GVIMRC_FILE2
  329.          && do_source((char_u *)USR_GVIMRC_FILE2, TRUE, FALSE) == FAIL
  330. #endif
  331.                 )
  332.         {
  333. #ifdef USR_GVIMRC_FILE3
  334.         (void)do_source((char_u *)USR_GVIMRC_FILE3, TRUE, FALSE);
  335. #endif
  336.         }
  337.  
  338.         /*
  339.          * Read initialization commands from ".gvimrc" in current
  340.          * directory.  This is only done if the 'exrc' option is set.
  341.          * Because of security reasons we disallow shell and write
  342.          * commands now, except for unix if the file is owned by the user
  343.          * or 'secure' option has been reset in environment of global
  344.          * ".gvimrc".
  345.          * Only do this if GVIMRC_FILE is not the same as USR_GVIMRC_FILE,
  346.          * USR_GVIMRC_FILE2, USR_GVIMRC_FILE3 or SYS_GVIMRC_FILE.
  347.          */
  348.         if (p_exrc)
  349.         {
  350. #ifdef UNIX
  351.         {
  352.             struct stat s;
  353.  
  354.             /* if ".gvimrc" file is not owned by user, set 'secure'
  355.              * mode */
  356.             if (mch_stat(GVIMRC_FILE, &s) || s.st_uid != getuid())
  357.             secure = p_secure;
  358.         }
  359. #else
  360.         secure = p_secure;
  361. #endif
  362.  
  363.         if (       fullpathcmp((char_u *)USR_GVIMRC_FILE,
  364.                      (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
  365. #ifdef SYS_GVIMRC_FILE
  366.             && fullpathcmp((char_u *)SYS_GVIMRC_FILE,
  367.                      (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
  368. #endif
  369. #ifdef USR_GVIMRC_FILE2
  370.             && fullpathcmp((char_u *)USR_GVIMRC_FILE2,
  371.                      (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
  372. #endif
  373. #ifdef USR_GVIMRC_FILE3
  374.             && fullpathcmp((char_u *)USR_GVIMRC_FILE3,
  375.                      (char_u *)GVIMRC_FILE, FALSE) != FPC_SAME
  376. #endif
  377.             )
  378.             do_source((char_u *)GVIMRC_FILE, TRUE, FALSE);
  379.  
  380.         if (secure == 2)
  381.             need_wait_return = TRUE;
  382.         secure = 0;
  383.         }
  384.     }
  385.  
  386.     if (need_wait_return || msg_didany)
  387.         wait_return(TRUE);
  388.  
  389.     --recursive;
  390.     }
  391.  
  392.     /* If recursive call opened the shell, return here from the first call */
  393.     if (gui.in_use)
  394.     return;
  395.  
  396.     /*
  397.      * Create the GUI shell.
  398.      */
  399.     gui.in_use = TRUE;        /* Must be set after menus have been set up */
  400.     if (gui_mch_init() == FAIL)
  401.     goto error;
  402.  
  403.     /* Avoid a delay for an error message that was printed in the terminal
  404.      * where Vim was started. */
  405.     emsg_on_display = FALSE;
  406.     msg_scrolled = 0;
  407.     need_wait_return = FALSE;
  408.     msg_didany = FALSE;
  409.  
  410.     /*
  411.      * Check validity of any generic resources that may have been loaded.
  412.      */
  413.     if (gui.border_width < 0)
  414.     gui.border_width = 0;
  415.  
  416.     /*
  417.      * Set up the fonts.  First use a font specified with "-fn" or "-font".
  418.      */
  419.     if (font_argument != NULL)
  420.     set_option_value((char_u *)"gfn", 0L, (char_u *)font_argument, 0);
  421.     if (
  422. #ifdef FEAT_XFONTSET
  423.         (*p_guifontset == NUL
  424.          || gui_init_font(p_guifontset, TRUE) == FAIL) &&
  425. #endif
  426.         gui_init_font(*p_guifont == NUL ? hl_get_font_name()
  427.                           : p_guifont, FALSE) == FAIL)
  428.     goto error2;
  429. #ifdef FEAT_MBYTE
  430.     if (gui_get_wide_font() == FAIL)
  431.     EMSG(_("E231: 'guifontwide' invalid"));
  432. #endif
  433.  
  434.     gui.num_cols = Columns;
  435.     gui.num_rows = Rows;
  436.     gui_reset_scroll_region();
  437.  
  438.     /* Create initial scrollbars */
  439.     FOR_ALL_WINDOWS(wp)
  440.     {
  441.     gui_create_scrollbar(&wp->w_scrollbars[SBAR_LEFT], SBAR_LEFT, wp);
  442.     gui_create_scrollbar(&wp->w_scrollbars[SBAR_RIGHT], SBAR_RIGHT, wp);
  443.     }
  444.     gui_create_scrollbar(&gui.bottom_sbar, SBAR_BOTTOM, NULL);
  445.  
  446. #ifdef FEAT_MENU
  447.     gui_create_initial_menus(root_menu);
  448. #endif
  449. #ifdef FEAT_SUN_WORKSHOP
  450.     if (usingSunWorkShop)
  451.     workshop_init();
  452. #endif
  453.  
  454.     /* Configure the desired menu and scrollbars */
  455.     gui_init_which_components(NULL);
  456.  
  457.     /* All components of the GUI have been created now */
  458.     gui.shell_created = TRUE;
  459.  
  460. #ifndef FEAT_GUI_GTK
  461.     /* Set the shell size, adjusted for the screen size.  For GTK this only
  462.      * works after the shell has been opened, thus it is further down. */
  463.     gui_set_shellsize(FALSE, TRUE);
  464. #endif
  465. #if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
  466.     /* Need to set the size of the menubar after all the menus have been
  467.      * created. */
  468.     gui_mch_compute_menu_height((Widget)0);
  469. #endif
  470.  
  471.     /*
  472.      * Actually open the GUI shell.
  473.      */
  474.     if (gui_mch_open() != FAIL)
  475.     {
  476. #ifdef FEAT_TITLE
  477.     maketitle();
  478.     resettitle();
  479. #endif
  480.     init_gui_options();
  481. #ifdef FEAT_GUI_GTK
  482.     /* Give GTK+ a chance to put all widget's into place. */
  483.     gui_mch_update();
  484.     /* Now make sure the shell fits on the screen. */
  485.     gui_set_shellsize(FALSE, TRUE);
  486. #endif
  487.     return;
  488.     }
  489.  
  490. error2:
  491. #ifdef FEAT_GUI_X11
  492.     /* undo gui_mch_init() */
  493.     gui_mch_uninit();
  494. #endif
  495.  
  496. error:
  497.     gui.in_use = FALSE;
  498.     clip_init(FALSE);
  499. }
  500.  
  501.  
  502.     void
  503. gui_exit(rc)
  504.     int        rc;
  505. {
  506. #ifndef __BEOS__
  507.     /* don't free the fonts, it leads to a BUS error
  508.      * richard@whitequeen.com Jul 99 */
  509.     free_highlight_fonts();
  510. #endif
  511.     gui.in_use = FALSE;
  512.     gui_mch_exit(rc);
  513. }
  514.  
  515. #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_MSWIN) \
  516.     || defined(FEAT_GUI_PHOTON) || defined(PROTO)
  517. /*
  518.  * Called when the GUI shell is closed by the user.  If there are no changed
  519.  * files Vim exits, otherwise there will be a dialog to ask the user what to
  520.  * do.
  521.  * When this function returns, Vim should NOT exit!
  522.  */
  523.     void
  524. gui_shell_closed()
  525. {
  526.     cmdmod_T        save_cmdmod;
  527.  
  528.     save_cmdmod = cmdmod;
  529.  
  530.     /* Only exit when there are no changed files */
  531.     exiting = TRUE;
  532. # ifdef FEAT_BROWSE
  533.     cmdmod.browse = TRUE;
  534. # endif
  535. # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
  536.     cmdmod.confirm = TRUE;
  537. # endif
  538.     /* If there are changed buffers, present the user with a dialog if
  539.      * possible, otherwise give an error message. */
  540.     if (!check_changed_any(FALSE))
  541.     getout(0);
  542.  
  543.     exiting = FALSE;
  544.     cmdmod = save_cmdmod;
  545.     setcursor();        /* position cursor */
  546.     out_flush();
  547. }
  548. #endif
  549.  
  550. /*
  551.  * Set the font.  "font_list" is a a comma separated list of font names.  The
  552.  * first font name that works is used.  If none is found, use the default
  553.  * font.
  554.  * If "fontset" is TRUE, the "font_list" is used as one name for the fontset.
  555.  * Return OK when able to set the font.  When it failed FAIL is returned and
  556.  * the fonts are unchanged.
  557.  */
  558. /*ARGSUSED*/
  559.     int
  560. gui_init_font(font_list, fontset)
  561.     char_u    *font_list;
  562.     int        fontset;
  563. {
  564. #define FONTLEN 320
  565.     char_u    font_name[FONTLEN];
  566.     int        font_list_empty = FALSE;
  567.     int        ret = FAIL;
  568.  
  569.     if (!gui.in_use)
  570.     return FAIL;
  571.  
  572.     font_name[0] = NUL;
  573.     if (*font_list == NUL)
  574.     font_list_empty = TRUE;
  575.     else
  576.     {
  577. #ifdef FEAT_XFONTSET
  578.     /* When using a fontset, the whole list of fonts is one name. */
  579.     if (fontset)
  580.         ret = gui_mch_init_font(font_list, TRUE);
  581.     else
  582. #endif
  583.         while (*font_list != NUL)
  584.         {
  585.         /* Isolate one comma separated font name. */
  586.         (void)copy_option_part(&font_list, font_name, FONTLEN, ",");
  587.         if (gui_mch_init_font(font_name, FALSE) == OK)
  588.         {
  589. #ifdef FEAT_MBYTE
  590.             /* If it's a Unicode font, try setting 'guifontwide' to a
  591.              * similar double-width font. */
  592.             if ((p_guifontwide == NULL || *p_guifontwide == NUL)
  593.                 && strstr((char *)font_name, "10646") != NULL)
  594.             set_guifontwide(font_name);
  595. #endif
  596.             ret = OK;
  597.             break;
  598.         }
  599.         }
  600.     }
  601.  
  602.     if (ret != OK
  603.         && STRCMP(font_list, "*") != 0
  604.         && (font_list_empty || gui.norm_font == NOFONT))
  605.     {
  606.     /*
  607.      * Couldn't load any font in 'font_list', keep the current font if
  608.      * there is one.  If 'font_list' is empty, or if there is no current
  609.      * font, tell gui_mch_init_font() to try to find a font we can load.
  610.      */
  611.     ret = gui_mch_init_font(NULL, FALSE);
  612.     }
  613.  
  614.     if (ret == OK)
  615.     {
  616.     /* Set normal font as current font */
  617. #ifdef FEAT_XFONTSET
  618.     if (gui.fontset != NOFONTSET)
  619.         gui_mch_set_fontset(gui.fontset);
  620.     else
  621. #endif
  622.         gui_mch_set_font(gui.norm_font);
  623.     gui_set_shellsize(FALSE,
  624. #ifdef MSWIN
  625.         TRUE
  626. #else
  627.         FALSE
  628. #endif
  629.         );
  630.     }
  631.  
  632.     return ret;
  633. }
  634.  
  635. #if defined(FEAT_MBYTE) || defined(PROTO)
  636. /*
  637.  * Try setting 'guifontwide' to a font twice as wide as "name".
  638.  */
  639.     static void
  640. set_guifontwide(name)
  641.     char_u    *name;
  642. {
  643.     int        i = 0;
  644.     char_u    wide_name[FONTLEN + 10]; /* room for 2 * width and '*' */
  645.     char_u    *wp = NULL;
  646.     char_u    *p;
  647.     GuiFont    font;
  648.  
  649.     wp = wide_name;
  650.     for (p = name; *p != NUL; ++p)
  651.     {
  652.     *wp++ = *p;
  653.     if (*p == '-')
  654.     {
  655.         ++i;
  656.         if (i == 6)        /* font type: change "--" to "-*-" */
  657.         {
  658.         if (p[1] == '-')
  659.             *wp++ = '*';
  660.         }
  661.         else if (i == 12)    /* found the width */
  662.         {
  663.         ++p;
  664.         i = getdigits(&p);
  665.         if (i != 0)
  666.         {
  667.             /* Double the width specification. */
  668.             sprintf((char *)wp, "%d%s", i * 2, p);
  669.             font = gui_mch_get_font(wide_name, FALSE);
  670.             if (font != NOFONT)
  671.             {
  672.             gui.wide_font = font;
  673.             set_string_option_direct((char_u *)"gfw", -1,
  674.                              wide_name, OPT_FREE);
  675.             }
  676.         }
  677.         break;
  678.         }
  679.     }
  680.     }
  681. }
  682.  
  683. /*
  684.  * Get the font for 'guifontwide'.
  685.  * Return FAIL for an invalid font name.
  686.  */
  687.     int
  688. gui_get_wide_font()
  689. {
  690.     GuiFont    font = NOFONT;
  691.     char_u    font_name[FONTLEN];
  692.     char_u    *p;
  693.  
  694.     if (!gui.in_use)        /* Can't allocate font yet, assume it's OK. */
  695.     return OK;        /* Will give an error message later. */
  696.  
  697.     if (p_guifontwide != NULL && *p_guifontwide != NUL)
  698.     {
  699.     for (p = p_guifontwide; *p != NUL; )
  700.     {
  701.         /* Isolate one comma separated font name. */
  702.         (void)copy_option_part(&p, font_name, FONTLEN, ",");
  703.         font = gui_mch_get_font(font_name, FALSE);
  704.         if (font != NOFONT)
  705.         break;
  706.     }
  707.     if (font == NOFONT)
  708.         return FAIL;
  709.     }
  710.  
  711.     gui_mch_free_font(gui.wide_font);
  712.     gui.wide_font = font;
  713.     return OK;
  714. }
  715. #endif
  716.  
  717.     void
  718. gui_set_cursor(row, col)
  719.     int        row;
  720.     int        col;
  721. {
  722.     gui.row = row;
  723.     gui.col = col;
  724. }
  725.  
  726. /*
  727.  * gui_check_pos - check if the cursor is on the screen.
  728.  */
  729.     static void
  730. gui_check_pos()
  731. {
  732.     if (gui.row >= screen_Rows)
  733.     gui.row = screen_Rows - 1;
  734.     if (gui.col >= screen_Columns)
  735.     gui.col = screen_Columns - 1;
  736.     if (gui.cursor_row >= screen_Rows || gui.cursor_col >= screen_Columns)
  737.     gui.cursor_is_valid = FALSE;
  738. }
  739.  
  740. /*
  741.  * Redraw the cursor if necessary or when forced.
  742.  * Careful: The contents of ScreenLines[] must match what is on the screen,
  743.  * otherwise this goes wrong.  May need to call out_flush() first.
  744.  */
  745.     void
  746. gui_update_cursor(force, clear_selection)
  747.     int        force;        /* when TRUE, update even when not moved */
  748.     int        clear_selection;/* clear selection under cursor */
  749. {
  750.     int        cur_width = 0;
  751.     int        cur_height = 0;
  752.     int        old_hl_mask;
  753.     int        idx;
  754.     int        id;
  755.     guicolor_T    cfg, cbg, cc;    /* cursor fore-/background color */
  756.     int        cattr;        /* cursor attributes */
  757.     int        attr;
  758.     attrentry_T *aep = NULL;
  759.  
  760.     /* Don't update the cursor when halfway busy scrolling.
  761.      * ScreenLines[] isn't valid then. */
  762.     if (!can_update_cursor)
  763.     return;
  764.  
  765.     gui_check_pos();
  766.     if (!gui.cursor_is_valid || force
  767.             || gui.row != gui.cursor_row || gui.col != gui.cursor_col)
  768.     {
  769.     gui_undraw_cursor();
  770.     if (gui.row < 0)
  771.         return;
  772. #ifdef USE_IM_CONTROL
  773.     if (gui.row != gui.cursor_row || gui.col != gui.cursor_col)
  774.         im_set_position(gui.row, gui.col);
  775. #endif
  776.     gui.cursor_row = gui.row;
  777.     gui.cursor_col = gui.col;
  778.     gui.cursor_is_valid = TRUE;
  779.  
  780.     /* Only write to the screen after ScreenLines[] has been initialized */
  781.     if (!screen_cleared || ScreenLines == NULL)
  782.         return;
  783.  
  784.     /* Clear the selection if we are about to write over it */
  785.     if (clear_selection)
  786.         clip_may_clear_selection(gui.row, gui.row);
  787.     /* Check that the cursor is inside the shell (resizing may have made
  788.      * it invalid) */
  789.     if (gui.row >= screen_Rows || gui.col >= screen_Columns)
  790.         return;
  791.  
  792.     /*
  793.      * How the cursor is drawn depends on the current mode.
  794.      */
  795.     idx = get_shape_idx(FALSE);
  796.     if (State & LANGMAP)
  797.         id = shape_table[idx].id_lm;
  798.     else
  799.         id = shape_table[idx].id;
  800.  
  801.     /* get the colors and attributes for the cursor.  Default is inverted */
  802.     cfg = (guicolor_T)-1;
  803.     cbg = (guicolor_T)-1;
  804.     cattr = HL_INVERSE;
  805.     gui_mch_set_blinking(shape_table[idx].blinkwait,
  806.                  shape_table[idx].blinkon,
  807.                  shape_table[idx].blinkoff);
  808.     if (id > 0)
  809.     {
  810.         cattr = syn_id2colors(id, &cfg, &cbg);
  811. #if defined(USE_IM_CONTROL) || defined(FEAT_HANGULIN)
  812.         {
  813.         static int iid;
  814.         guicolor_T fg, bg;
  815.  
  816.         if (im_get_status())
  817.         {
  818.             iid = syn_name2id((char_u *)"CursorIM");
  819.             if (iid > 0)
  820.             {
  821.             syn_id2colors(iid, &fg, &bg);
  822.             if (bg > 0)
  823.                 cbg = bg;
  824.             }
  825.         }
  826.         }
  827. #endif
  828.         --cbg;
  829.         --cfg;
  830.     }
  831.  
  832.     /*
  833.      * Get the attributes for the character under the cursor.
  834.      * When no cursor color was given, use the character color.
  835.      */
  836.     attr = ScreenAttrs[LineOffset[gui.row] + gui.col];
  837.     if (attr > HL_ALL)
  838.         aep = syn_gui_attr2entry(attr);
  839.     if (aep != NULL)
  840.     {
  841.         attr = aep->ae_attr;
  842.         if (cfg < 0)
  843.         cfg = ((attr & HL_INVERSE)  ? aep->ae_u.gui.bg_color
  844.                         : aep->ae_u.gui.fg_color) - 1;
  845.         if (cbg < 0)
  846.         cbg = ((attr & HL_INVERSE)  ? aep->ae_u.gui.fg_color
  847.                         : aep->ae_u.gui.bg_color) - 1;
  848.     }
  849.     if (cfg < 0)
  850.         cfg = (attr & HL_INVERSE) ? gui.back_pixel : gui.norm_pixel;
  851.     if (cbg < 0)
  852.         cbg = (attr & HL_INVERSE) ? gui.norm_pixel : gui.back_pixel;
  853.  
  854. #ifdef FEAT_XIM
  855.     if (aep != NULL)
  856.     {
  857.         xim_bg_color = ((attr & HL_INVERSE) ? aep->ae_u.gui.fg_color
  858.                         : aep->ae_u.gui.bg_color) - 1;
  859.         xim_fg_color = ((attr & HL_INVERSE) ? aep->ae_u.gui.bg_color
  860.                         : aep->ae_u.gui.fg_color) - 1;
  861.         if (xim_bg_color < 0)
  862.         xim_bg_color = (attr & HL_INVERSE) ? gui.norm_pixel
  863.                            : gui.back_pixel;
  864.         if (xim_fg_color < 0)
  865.         xim_fg_color = (attr & HL_INVERSE) ? gui.back_pixel
  866.                            : gui.norm_pixel;
  867.     }
  868.     else
  869.     {
  870.         xim_bg_color = (attr & HL_INVERSE) ? gui.norm_pixel
  871.                            : gui.back_pixel;
  872.         xim_fg_color = (attr & HL_INVERSE) ? gui.back_pixel
  873.                            : gui.norm_pixel;
  874.     }
  875. #endif
  876.  
  877.     attr &= ~HL_INVERSE;
  878.     if (cattr & HL_INVERSE)
  879.     {
  880.         cc = cbg;
  881.         cbg = cfg;
  882.         cfg = cc;
  883.     }
  884.     cattr &= ~HL_INVERSE;
  885.  
  886.     /*
  887.      * When we don't have window focus, draw a hollow cursor.
  888.      */
  889.     if (!gui.in_focus)
  890.     {
  891.         gui_mch_draw_hollow_cursor(cbg);
  892.         return;
  893.     }
  894.  
  895.     old_hl_mask = gui.highlight_mask;
  896.     if (shape_table[idx].shape == SHAPE_BLOCK
  897. #ifdef FEAT_HANGULIN
  898.         || composing_hangul
  899. #endif
  900.         )
  901.     {
  902.         /*
  903.          * Draw the text character with the cursor colors.    Use the
  904.          * character attributes plus the cursor attributes.
  905.          */
  906.         gui.highlight_mask = (cattr | attr);
  907. #ifdef FEAT_HANGULIN
  908.         if (composing_hangul)
  909.         gui_outstr_nowrap(composing_hangul_buffer, 2,
  910.             GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR, cfg, cbg, 0);
  911.         else
  912. #endif
  913.         gui_screenchar(LineOffset[gui.row] + gui.col,
  914.             GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR, cfg, cbg, 0);
  915.     }
  916.     else
  917.     {
  918.         /*
  919.          * First draw the partial cursor, then overwrite with the text
  920.          * character, using a transparent background.
  921.          */
  922.         if (shape_table[idx].shape == SHAPE_VER)
  923.         {
  924.         cur_height = gui.char_height;
  925.         cur_width = (gui.char_width * shape_table[idx].percentage
  926.                                   + 99) / 100;
  927.         }
  928.         else
  929.         {
  930.         cur_height = (gui.char_height * shape_table[idx].percentage
  931.                                   + 99) / 100;
  932.         cur_width = gui.char_width;
  933. #ifdef FEAT_MBYTE
  934.         if ((*mb_off2cells)(LineOffset[gui.row] + gui.col) > 1)
  935.             cur_width += gui.char_width;
  936. #endif
  937.         }
  938.         gui_mch_draw_part_cursor(cur_width, cur_height, cbg);
  939.  
  940. #ifndef FEAT_GUI_MSWIN        /* doesn't seem to work for MSWindows */
  941.         gui.highlight_mask = ScreenAttrs[LineOffset[gui.row] + gui.col];
  942.         gui_screenchar(LineOffset[gui.row] + gui.col,
  943.             GUI_MON_TRS_CURSOR | GUI_MON_NOCLEAR,
  944.             (guicolor_T)0, (guicolor_T)0, 0);
  945. #endif
  946.     }
  947.     gui.highlight_mask = old_hl_mask;
  948.     }
  949. }
  950.  
  951. #if defined(FEAT_MENU) || defined(PROTO)
  952.     void
  953. gui_position_menu()
  954. {
  955. # if !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MOTIF)
  956.     if (gui.menu_is_active && gui.in_use)
  957.     gui_mch_set_menu_pos(0, 0, gui.menu_width, gui.menu_height);
  958. # endif
  959. }
  960. #endif
  961.  
  962. /*
  963.  * Position the various GUI components (text area, menu).  The vertical
  964.  * scrollbars are NOT handled here.  See gui_update_scrollbars().
  965.  */
  966. /*ARGSUSED*/
  967.     static void
  968. gui_position_components(total_width)
  969.     int        total_width;
  970. {
  971.     int        text_area_x;
  972.     int        text_area_y;
  973.     int        text_area_width;
  974.     int        text_area_height;
  975.  
  976.     /* avoid that moving components around generates events */
  977.     ++hold_gui_events;
  978.  
  979.     text_area_x = 0;
  980.     if (gui.which_scrollbars[SBAR_LEFT])
  981.     text_area_x += gui.scrollbar_width;
  982.  
  983.     text_area_y = 0;
  984. #if defined(FEAT_MENU) && !(defined(FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON))
  985.     gui.menu_width = total_width;
  986.     if (gui.menu_is_active)
  987.     text_area_y += gui.menu_height;
  988. #endif
  989. #if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_MSWIN)
  990.     if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
  991.     text_area_y = TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT;
  992. #endif
  993.  
  994. #if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA))
  995.     if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
  996.     {
  997. # ifdef FEAT_GUI_ATHENA
  998.     gui_mch_set_toolbar_pos(0, text_area_y,
  999.                 gui.menu_width, gui.toolbar_height);
  1000. # endif
  1001.     text_area_y += gui.toolbar_height;
  1002.     }
  1003. #endif
  1004.  
  1005.     text_area_width = gui.num_cols * gui.char_width + gui.border_offset * 2;
  1006.     text_area_height = gui.num_rows * gui.char_height + gui.border_offset * 2;
  1007.  
  1008.     gui_mch_set_text_area_pos(text_area_x,
  1009.                   text_area_y,
  1010.                   text_area_width,
  1011.                   text_area_height
  1012. #ifdef FEAT_XIM
  1013.                   + xim_get_status_area_height()
  1014. #endif
  1015.                   );
  1016. #ifdef FEAT_MENU
  1017.     gui_position_menu();
  1018. #endif
  1019.     if (gui.which_scrollbars[SBAR_BOTTOM])
  1020.     gui_mch_set_scrollbar_pos(&gui.bottom_sbar,
  1021.                   text_area_x,
  1022.                   text_area_y + text_area_height,
  1023.                   text_area_width,
  1024.                   gui.scrollbar_height);
  1025.     gui.left_sbar_x = 0;
  1026.     gui.right_sbar_x = text_area_x + text_area_width;
  1027.  
  1028.     --hold_gui_events;
  1029. }
  1030.  
  1031.     int
  1032. gui_get_base_width()
  1033. {
  1034.     int        base_width;
  1035.  
  1036. #ifdef FEAT_FOOTER
  1037.     base_width = 4 * gui.border_offset;
  1038. #else
  1039.     base_width = 2 * gui.border_offset;
  1040. #endif
  1041.     if (gui.which_scrollbars[SBAR_LEFT])
  1042.     base_width += gui.scrollbar_width;
  1043.     if (gui.which_scrollbars[SBAR_RIGHT])
  1044.     base_width += gui.scrollbar_width;
  1045.     return base_width;
  1046. }
  1047.  
  1048.     int
  1049. gui_get_base_height()
  1050. {
  1051.     int        base_height;
  1052.  
  1053.     base_height = 2 * gui.border_offset;
  1054.     if (gui.which_scrollbars[SBAR_BOTTOM])
  1055.     base_height += gui.scrollbar_height;
  1056. #ifdef FEAT_GUI_GTK
  1057.     /* We can't take the sizes properly into account until anything is
  1058.      * realized.  Therefore we recalculate all the values here just before
  1059.      * setting the size. (--mdcki) */
  1060. #else
  1061. # ifdef FEAT_MENU
  1062.     if (gui.menu_is_active)
  1063.     base_height += gui.menu_height;
  1064. # endif
  1065. # ifdef FEAT_TOOLBAR
  1066.     if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
  1067. #  if defined(FEAT_GUI_MSWIN) && defined(FEAT_TOOLBAR)
  1068.     base_height += (TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT);
  1069. #  else
  1070.     base_height += gui.toolbar_height;
  1071. #  endif
  1072. # endif
  1073. # ifdef FEAT_FOOTER
  1074.     if (vim_strchr(p_go, GO_FOOTER) != NULL)
  1075.     base_height += gui.footer_height;
  1076. # endif
  1077. # if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
  1078.     base_height += gui_mch_text_area_extra_height();
  1079. # endif
  1080. #endif
  1081.     return base_height;
  1082. }
  1083.  
  1084. /*
  1085.  * Should be called after the GUI shell has been resized.  Its arguments are
  1086.  * the new width and height of the shell in pixels.
  1087.  */
  1088.     void
  1089. gui_resize_shell(pixel_width, pixel_height)
  1090.     int        pixel_width;
  1091.     int        pixel_height;
  1092. {
  1093.     static int    busy = FALSE;
  1094.  
  1095.     if (!gui.shell_created)        /* ignore when still initializing */
  1096.     return;
  1097.  
  1098.     /*
  1099.      * Can't resize the screen while it is being redrawn.  Remember the new
  1100.      * size and handle it later.
  1101.      */
  1102.     if (updating_screen || busy)
  1103.     {
  1104.     new_pixel_width = pixel_width;
  1105.     new_pixel_height = pixel_height;
  1106.     return;
  1107.     }
  1108.  
  1109. again:
  1110.     busy = TRUE;
  1111.  
  1112. #ifdef FEAT_GUI_BEOS
  1113.     vim_lock_screen();
  1114. #endif
  1115.  
  1116.     /* Flush pending output before redrawing */
  1117.     out_flush();
  1118.  
  1119.     gui.num_cols = (pixel_width - gui_get_base_width()) / gui.char_width;
  1120.     gui.num_rows = (pixel_height - gui_get_base_height()
  1121. #if !defined(FEAT_GUI_PHOTON) && !defined(FEAT_GUI_MSWIN)
  1122.                     + (gui.char_height / 2)
  1123. #endif
  1124.                     ) / gui.char_height;
  1125.  
  1126.     gui_position_components(pixel_width);
  1127.  
  1128.     gui_reset_scroll_region();
  1129.     /*
  1130.      * At the "more" and ":confirm" prompt there is no redraw, put the cursor
  1131.      * at the last line here (why does it have to be one row too low?).
  1132.      */
  1133.     if (State == ASKMORE || State == CONFIRM)
  1134.     gui.row = gui.num_rows;
  1135.  
  1136.     if (gui.num_rows != screen_Rows || gui.num_cols != screen_Columns)
  1137.     shell_resized();
  1138.  
  1139. #ifdef FEAT_GUI_BEOS
  1140.     vim_unlock_screen();
  1141. #endif
  1142.  
  1143.     gui_update_scrollbars(TRUE);
  1144.     gui_update_cursor(FALSE, TRUE);
  1145. #ifdef FEAT_XIM
  1146.     xim_set_status_area();
  1147. #endif
  1148.  
  1149.     busy = FALSE;
  1150.     /*
  1151.      * We could have been called again while redrawing the screen.
  1152.      * Need to do it all again with the latest size then.
  1153.      */
  1154.     if (new_pixel_height)
  1155.     {
  1156.     pixel_width = new_pixel_width;
  1157.     pixel_height = new_pixel_height;
  1158.     new_pixel_width = 0;
  1159.     new_pixel_height = 0;
  1160.     goto again;
  1161.     }
  1162. }
  1163.  
  1164. /*
  1165.  * Check if gui_resize_shell() must be called.
  1166.  */
  1167.     void
  1168. gui_may_resize_shell()
  1169. {
  1170.     int        h, w;
  1171.  
  1172.     if (new_pixel_height)
  1173.     {
  1174.     /* careful: gui_resize_shell() may postpone the resize again if we
  1175.      * were called indirectly by it */
  1176.     w = new_pixel_width;
  1177.     h = new_pixel_height;
  1178.     new_pixel_width = 0;
  1179.     new_pixel_height = 0;
  1180.     gui_resize_shell(w, h);
  1181.     }
  1182. }
  1183.  
  1184.     int
  1185. gui_get_shellsize()
  1186. {
  1187.     Rows = gui.num_rows;
  1188.     Columns = gui.num_cols;
  1189.     return OK;
  1190. }
  1191.  
  1192. /*
  1193.  * Set the size of the Vim shell according to Rows and Columns.
  1194.  */
  1195. /*ARGSUSED*/
  1196.     void
  1197. gui_set_shellsize(mustset, fit_to_display)
  1198.     int        mustset;        /* set by the user */
  1199.     int        fit_to_display;
  1200. {
  1201.     int        base_width;
  1202.     int        base_height;
  1203.     int        width;
  1204.     int        height;
  1205.     int        min_width;
  1206.     int        min_height;
  1207.     int        screen_w;
  1208.     int        screen_h;
  1209.  
  1210.     if (!gui.shell_created)
  1211.     return;
  1212.  
  1213. #ifdef MSWIN
  1214.     /* If not setting to a user specified size and maximized, calculate the
  1215.      * number of characters that fit in the maximized window. */
  1216.     if (!mustset && gui_mch_maximized())
  1217.     {
  1218.     gui_mch_newfont();
  1219.     return;
  1220.     }
  1221. #endif
  1222.  
  1223.     base_width = gui_get_base_width();
  1224.     base_height = gui_get_base_height();
  1225. #ifdef USE_SUN_WORKSHOP
  1226.     if (!mustset && usingSunWorkShop
  1227.                 && workshop_get_width_height(&width, &height))
  1228.     {
  1229.     Columns = (width - base_width + gui.char_width - 1) / gui.char_width;
  1230.     Rows = (height - base_height + gui.char_height - 1) / gui.char_height;
  1231.     }
  1232.     else
  1233. #endif
  1234.     {
  1235.     width = Columns * gui.char_width + base_width;
  1236.     height = Rows * gui.char_height + base_height;
  1237.     }
  1238.  
  1239.     if (fit_to_display)
  1240.     {
  1241.     gui_mch_get_screen_dimensions(&screen_w, &screen_h);
  1242.     if (width > screen_w)
  1243.     {
  1244.         Columns = (screen_w - base_width) / gui.char_width;
  1245.         if (Columns < MIN_COLUMNS)
  1246.         Columns = MIN_COLUMNS;
  1247.         width = Columns * gui.char_width + base_width;
  1248.     }
  1249.     if (height > screen_h)
  1250.     {
  1251.         Rows = (screen_h - base_height) / gui.char_height;
  1252.         check_shellsize();
  1253.         height = Rows * gui.char_height + base_height;
  1254.     }
  1255.     }
  1256.     gui.num_cols = Columns;
  1257.     gui.num_rows = Rows;
  1258.  
  1259.     min_width = base_width + MIN_COLUMNS * gui.char_width;
  1260.     min_height = base_height + MIN_LINES * gui.char_height;
  1261.  
  1262.     gui_mch_set_shellsize(width, height, min_width, min_height,
  1263.                              base_width, base_height);
  1264.     gui_position_components(width);
  1265.     gui_update_scrollbars(TRUE);
  1266.     gui_reset_scroll_region();
  1267. }
  1268.  
  1269. /*
  1270.  * Called when Rows and/or Columns has changed.
  1271.  */
  1272.     void
  1273. gui_new_shellsize()
  1274. {
  1275.     gui_reset_scroll_region();
  1276. }
  1277.  
  1278. /*
  1279.  * Make scroll region cover whole screen.
  1280.  */
  1281.     void
  1282. gui_reset_scroll_region()
  1283. {
  1284.     gui.scroll_region_top = 0;
  1285.     gui.scroll_region_bot = gui.num_rows - 1;
  1286.     gui.scroll_region_left = 0;
  1287.     gui.scroll_region_right = gui.num_cols - 1;
  1288. }
  1289.  
  1290.     void
  1291. gui_start_highlight(mask)
  1292.     int        mask;
  1293. {
  1294.     if (mask > HL_ALL)            /* highlight code */
  1295.     gui.highlight_mask = mask;
  1296.     else                /* mask */
  1297.     gui.highlight_mask |= mask;
  1298. }
  1299.  
  1300.     void
  1301. gui_stop_highlight(mask)
  1302.     int        mask;
  1303. {
  1304.     if (mask > HL_ALL)            /* highlight code */
  1305.     gui.highlight_mask = HL_NORMAL;
  1306.     else                /* mask */
  1307.     gui.highlight_mask &= ~mask;
  1308. }
  1309.  
  1310. /*
  1311.  * Clear a rectangular region of the screen from text pos (row1, col1) to
  1312.  * (row2, col2) inclusive.
  1313.  */
  1314.     void
  1315. gui_clear_block(row1, col1, row2, col2)
  1316.     int        row1;
  1317.     int        col1;
  1318.     int        row2;
  1319.     int        col2;
  1320. {
  1321.     /* Clear the selection if we are about to write over it */
  1322.     clip_may_clear_selection(row1, row2);
  1323.  
  1324.     gui_mch_clear_block(row1, col1, row2, col2);
  1325.  
  1326.     /* Invalidate cursor if it was in this block */
  1327.     if (       gui.cursor_row >= row1 && gui.cursor_row <= row2
  1328.         && gui.cursor_col >= col1 && gui.cursor_col <= col2)
  1329.     gui.cursor_is_valid = FALSE;
  1330. }
  1331.  
  1332. /*
  1333.  * Write code to update the cursor later.  This avoids the need to flush the
  1334.  * output buffer before calling gui_update_cursor().
  1335.  */
  1336.     void
  1337. gui_update_cursor_later()
  1338. {
  1339.     OUT_STR(IF_EB("\033|s", ESC_STR "|s"));
  1340. }
  1341.  
  1342.     void
  1343. gui_write(s, len)
  1344.     char_u    *s;
  1345.     int        len;
  1346. {
  1347.     char_u    *p;
  1348.     int        arg1 = 0, arg2 = 0;
  1349.     /* this doesn't make sense, disabled until someone can explain why it
  1350.      * would be needed */
  1351. #if 0 && (defined(RISCOS) || defined(WIN16))
  1352.     int        force_cursor = TRUE;    /* JK230798, stop Vim being smart or
  1353.                        our redraw speed will suffer */
  1354. #else
  1355.     int        force_cursor = FALSE;    /* force cursor update */
  1356. #endif
  1357.     int        force_scrollbar = FALSE;
  1358.     static win_T    *old_curwin = NULL;
  1359.  
  1360. /* #define DEBUG_GUI_WRITE */
  1361. #ifdef DEBUG_GUI_WRITE
  1362.     {
  1363.     int i;
  1364.     char_u *str;
  1365.  
  1366.     printf("gui_write(%d):\n    ", len);
  1367.     for (i = 0; i < len; i++)
  1368.         if (s[i] == ESC)
  1369.         {
  1370.         if (i != 0)
  1371.             printf("\n    ");
  1372.         printf("<ESC>");
  1373.         }
  1374.         else
  1375.         {
  1376.         str = transchar(s[i]);
  1377.         if (str[0] && str[1])
  1378.             printf("<%s>", (char *)str);
  1379.         else
  1380.             printf("%s", (char *)str);
  1381.         }
  1382.     printf("\n");
  1383.     }
  1384. #endif
  1385.     while (len)
  1386.     {
  1387.     if (s[0] == ESC && s[1] == '|')
  1388.     {
  1389.         p = s + 2;
  1390.         if (isdigit(*p))
  1391.         {
  1392.         arg1 = getdigits(&p);
  1393.         if (p > s + len)
  1394.             break;
  1395.         if (*p == ';')
  1396.         {
  1397.             ++p;
  1398.             arg2 = getdigits(&p);
  1399.             if (p > s + len)
  1400.             break;
  1401.         }
  1402.         }
  1403.         switch (*p)
  1404.         {
  1405.         case 'C':    /* Clear screen */
  1406.             clip_scroll_selection(9999);
  1407.             gui_mch_clear_all();
  1408.             gui.cursor_is_valid = FALSE;
  1409.             force_scrollbar = TRUE;
  1410.             break;
  1411.         case 'M':    /* Move cursor */
  1412.             gui_set_cursor(arg1, arg2);
  1413.             break;
  1414.         case 's':    /* force cursor (shape) update */
  1415.             force_cursor = TRUE;
  1416.             break;
  1417.         case 'R':    /* Set scroll region */
  1418.             if (arg1 < arg2)
  1419.             {
  1420.             gui.scroll_region_top = arg1;
  1421.             gui.scroll_region_bot = arg2;
  1422.             }
  1423.             else
  1424.             {
  1425.             gui.scroll_region_top = arg2;
  1426.             gui.scroll_region_bot = arg1;
  1427.             }
  1428.             break;
  1429. #ifdef FEAT_VERTSPLIT
  1430.         case 'V':    /* Set vertical scroll region */
  1431.             if (arg1 < arg2)
  1432.             {
  1433.             gui.scroll_region_left = arg1;
  1434.             gui.scroll_region_right = arg2;
  1435.             }
  1436.             else
  1437.             {
  1438.             gui.scroll_region_left = arg2;
  1439.             gui.scroll_region_right = arg1;
  1440.             }
  1441.             break;
  1442. #endif
  1443.         case 'd':    /* Delete line */
  1444.             gui_delete_lines(gui.row, 1);
  1445.             break;
  1446.         case 'D':    /* Delete lines */
  1447.             gui_delete_lines(gui.row, arg1);
  1448.             break;
  1449.         case 'i':    /* Insert line */
  1450.             gui_insert_lines(gui.row, 1);
  1451.             break;
  1452.         case 'I':    /* Insert lines */
  1453.             gui_insert_lines(gui.row, arg1);
  1454.             break;
  1455.         case '$':    /* Clear to end-of-line */
  1456.             gui_clear_block(gui.row, gui.col, gui.row,
  1457.                                 (int)Columns - 1);
  1458.             break;
  1459.         case 'h':    /* Turn on highlighting */
  1460.             gui_start_highlight(arg1);
  1461.             break;
  1462.         case 'H':    /* Turn off highlighting */
  1463.             gui_stop_highlight(arg1);
  1464.             break;
  1465.         case 'f':    /* flash the window (visual bell) */
  1466.             gui_mch_flash(arg1 == 0 ? 20 : arg1);
  1467.             break;
  1468.         default:
  1469.             p = s + 1;    /* Skip the ESC */
  1470.             break;
  1471.         }
  1472.         len -= (int)(++p - s);
  1473.         s = p;
  1474.     }
  1475.     else if (
  1476. #ifdef EBCDIC
  1477.         CtrlChar(s[0]) != 0    /* Ctrl character */
  1478. #else
  1479.         s[0] < 0x20        /* Ctrl character */
  1480. #endif
  1481. #ifdef FEAT_SIGN_ICONS
  1482.         && s[0] != SIGN_BYTE
  1483. #endif
  1484.         )
  1485.     {
  1486.         if (s[0] == '\n')        /* NL */
  1487.         {
  1488.         gui.col = 0;
  1489.         if (gui.row < gui.scroll_region_bot)
  1490.             gui.row++;
  1491.         else
  1492.             gui_delete_lines(gui.scroll_region_top, 1);
  1493.         }
  1494.         else if (s[0] == '\r')    /* CR */
  1495.         {
  1496.         gui.col = 0;
  1497.         }
  1498.         else if (s[0] == '\b')    /* Backspace */
  1499.         {
  1500.         if (gui.col)
  1501.             --gui.col;
  1502.         }
  1503.         else if (s[0] == Ctrl_L)    /* cursor-right */
  1504.         {
  1505.         ++gui.col;
  1506.         }
  1507.         else if (s[0] == Ctrl_G)    /* Beep */
  1508.         {
  1509.         gui_mch_beep();
  1510.         }
  1511.         /* Other Ctrl character: shouldn't happen! */
  1512.  
  1513.         --len;    /* Skip this char */
  1514.         ++s;
  1515.     }
  1516.     else
  1517.     {
  1518.         p = s;
  1519.         while (len > 0 && (
  1520. #ifdef EBCDIC
  1521.             CtrlChar(*p) == 0
  1522. #else
  1523.             *p >= 0x20
  1524. #endif
  1525. #ifdef FEAT_SIGN_ICONS
  1526.             || *p == SIGN_BYTE
  1527. #endif
  1528.             ))
  1529.         {
  1530.         len--;
  1531.         p++;
  1532.         }
  1533.         gui_outstr(s, (int)(p - s));
  1534.         s = p;
  1535.     }
  1536.     }
  1537.  
  1538.     /* Don't update cursor when ScreenLines[] is invalid (busy scrolling). */
  1539.     if (can_update_cursor && force_cursor)
  1540.     gui_update_cursor(force_cursor, TRUE);
  1541.  
  1542.     /* When switching to another window the dragging must have stopped.
  1543.      * Required for GTK, dragged_sb isn't reset. */
  1544.     if (old_curwin != curwin)
  1545.     gui.dragged_sb = SBAR_NONE;
  1546.  
  1547.     /* Update the scrollbars after clearing the screen or when switched
  1548.      * to another window.
  1549.      * Update the horizontal scrollbar always, it's difficult to check all
  1550.      * situations where it might change. */
  1551.     if (force_scrollbar || old_curwin != curwin)
  1552.     gui_update_scrollbars(force_scrollbar);
  1553.     else
  1554.     gui_update_horiz_scrollbar(FALSE);
  1555.     old_curwin = curwin;
  1556.  
  1557.     /*
  1558.      * We need to make sure this is cleared since Athena doesn't tell us when
  1559.      * he is done dragging.  Do the same for GTK.
  1560.      */
  1561. #if defined(FEAT_GUI_ATHENA) || defined(FEAT_GUI_GTK)
  1562.     gui.dragged_sb = SBAR_NONE;
  1563. #endif
  1564.  
  1565.     gui_mch_flush();            /* In case vim decides to take a nap */
  1566. }
  1567.  
  1568. /*
  1569.  * When ScreenLines[] is invalid, updating the cursor should not be done, it
  1570.  * produces wrong results.  Call gui_dont_update_cursor() before that code and
  1571.  * gui_can_update_cursor() afterwards.
  1572.  */
  1573.     void
  1574. gui_dont_update_cursor()
  1575. {
  1576.     can_update_cursor = FALSE;
  1577. }
  1578.  
  1579.     void
  1580. gui_can_update_cursor()
  1581. {
  1582.     can_update_cursor = TRUE;
  1583.     /* No need to update the cursor right now, there is always more output
  1584.      * after scrolling. */
  1585. }
  1586.  
  1587.     static void
  1588. gui_outstr(s, len)
  1589.     char_u  *s;
  1590.     int        len;
  1591. {
  1592.     int        this_len;
  1593. #ifdef FEAT_MBYTE
  1594.     int        cells;
  1595. #endif
  1596.  
  1597.     if (len == 0)
  1598.     return;
  1599.  
  1600.     if (len < 0)
  1601.     len = (int)STRLEN(s);
  1602.  
  1603.     while (len > 0)
  1604.     {
  1605. #ifdef FEAT_MBYTE
  1606.     if (has_mbyte)
  1607.     {
  1608.         /* Find out how many chars fit in the current line. */
  1609.         cells = 0;
  1610.         for (this_len = 0; this_len < len; )
  1611.         {
  1612.         cells += (*mb_ptr2cells)(s + this_len);
  1613.         if (gui.col + cells > Columns)
  1614.             break;
  1615.         this_len += (*mb_ptr2len_check)(s + this_len);
  1616.         }
  1617.         if (this_len > len)
  1618.         this_len = len;        /* don't include following composing char */
  1619.     }
  1620.     else
  1621. #endif
  1622.         if (gui.col + len > Columns)
  1623.         this_len = Columns - gui.col;
  1624.     else
  1625.         this_len = len;
  1626.  
  1627.     gui_outstr_nowrap(s, this_len, 0, (guicolor_T)0, (guicolor_T)0, 0);
  1628.     s += this_len;
  1629.     len -= this_len;
  1630. #ifdef FEAT_MBYTE
  1631.     /* fill up for a double-width char that doesn't fit. */
  1632.     if (len > 0 && gui.col < Columns)
  1633.         gui_outstr_nowrap((char_u *)" ", 1,
  1634.                       0, (guicolor_T)0, (guicolor_T)0, 0);
  1635. #endif
  1636.     /* The cursor may wrap to the next line. */
  1637.     if (gui.col >= Columns)
  1638.     {
  1639.         gui.col = 0;
  1640.         gui.row++;
  1641.     }
  1642.     }
  1643. }
  1644.  
  1645. /*
  1646.  * Output one character (may be one or two display cells).
  1647.  * Caller must check for valid "off".
  1648.  */
  1649.     static void
  1650. gui_screenchar(off, flags, fg, bg, back)
  1651.     int        off;        /* Offset from start of screen */
  1652.     int        flags;
  1653.     guicolor_T    fg, bg;        /* colors for cursor */
  1654.     int        back;        /* backup this many chars when using bold trick */
  1655. {
  1656. #ifdef FEAT_MBYTE
  1657.     char_u    buf[MB_MAXBYTES + 1];
  1658.  
  1659.     /* Don't draw right halve of a double-width UTF-8 char. "cannot happen" */
  1660.     if (enc_utf8 && ScreenLines[off] == 0)
  1661.     return;
  1662.     if (enc_utf8 && ScreenLinesUC[off] != 0)
  1663.     /* Draw UTF-8 multi-byte character. */
  1664.     gui_outstr_nowrap(buf,
  1665.         utfc_char2bytes(off, buf),
  1666.         flags, fg, bg, 0);
  1667.     else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
  1668.     {
  1669.     buf[0] = ScreenLines[off];
  1670.     buf[1] = ScreenLines2[off];
  1671.     gui_outstr_nowrap(buf, 2, flags, fg, bg, 0);
  1672.     }
  1673.     else
  1674.     /* Draw non-multi-byte character or DBCS character. */
  1675.     gui_outstr_nowrap(ScreenLines + off,
  1676.         enc_dbcs ? (*mb_ptr2len_check)(ScreenLines + off) : 1,
  1677.         flags, fg, bg, back);
  1678. #else
  1679.     gui_outstr_nowrap(ScreenLines + off,
  1680.         1,
  1681.         flags, fg, bg, back);
  1682. #endif
  1683. }
  1684.  
  1685. /*
  1686.  * Output the given string at the current cursor position.  If the string is
  1687.  * too long to fit on the line, then it is truncated.
  1688.  * "flags":
  1689.  * GUI_MON_IS_CURSOR should only be used when this function is being called to
  1690.  * actually draw (an inverted) cursor.
  1691.  * GUI_MON_TRS_CURSOR is used to draw the cursor text with a transparant
  1692.  * background.
  1693.  */
  1694.     void
  1695. gui_outstr_nowrap(s, len, flags, fg, bg, back)
  1696.     char_u    *s;
  1697.     int        len;
  1698.     int        flags;
  1699.     guicolor_T    fg, bg;        /* colors for cursor */
  1700.     int        back;        /* backup this many chars when using bold trick */
  1701. {
  1702.     long_u    highlight_mask;
  1703.     long_u    hl_mask_todo;
  1704.     guicolor_T    fg_color;
  1705.     guicolor_T    bg_color;
  1706. #ifndef MSWIN16_FASTTEXT
  1707.     GuiFont    font = NOFONT;
  1708. # ifdef FEAT_XFONTSET
  1709.     GuiFontset    fontset = NOFONTSET;
  1710. # endif
  1711. #endif
  1712.     attrentry_T    *aep = NULL;
  1713.     int        draw_flags;
  1714.     int        col = gui.col;
  1715. #ifdef FEAT_SIGN_ICONS
  1716.     int        draw_sign = FALSE;
  1717. #endif
  1718.  
  1719.     if (len < 0)
  1720.     len = (int)STRLEN(s);
  1721.     if (len == 0)
  1722.     return;
  1723.  
  1724. #ifdef FEAT_SIGN_ICONS
  1725.     if (*s == SIGN_BYTE)
  1726.     {
  1727.     /* draw spaces instead */
  1728.     s = (char_u *)"  ";
  1729.     if (len == 1 && col > 0)
  1730.         --col;
  1731.     len = 2;
  1732.     draw_sign = TRUE;
  1733.     highlight_mask = 0;
  1734.     }
  1735.     else
  1736. #endif
  1737.     if (gui.highlight_mask > HL_ALL)
  1738.     {
  1739.     aep = syn_gui_attr2entry(gui.highlight_mask);
  1740.     if (aep == NULL)        /* highlighting not set */
  1741.         highlight_mask = 0;
  1742.     else
  1743.         highlight_mask = aep->ae_attr;
  1744.     }
  1745.     else
  1746.     highlight_mask = gui.highlight_mask;
  1747.     hl_mask_todo = highlight_mask;
  1748.  
  1749. #ifndef MSWIN16_FASTTEXT
  1750.     /* Set the font */
  1751.     if (aep != NULL && aep->ae_u.gui.font != NOFONT)
  1752.     font = aep->ae_u.gui.font;
  1753. # ifdef FEAT_XFONTSET
  1754.     else if (aep != NULL && aep->ae_u.gui.fontset != NOFONTSET)
  1755.     fontset = aep->ae_u.gui.fontset;
  1756. # endif
  1757.     else
  1758.     {
  1759. # ifdef FEAT_XFONTSET
  1760.     if (gui.fontset != NOFONTSET)
  1761.         fontset = gui.fontset;
  1762.     else
  1763. # endif
  1764.         if (hl_mask_todo & (HL_BOLD | HL_STANDOUT))
  1765.     {
  1766.         if ((hl_mask_todo & HL_ITALIC) && gui.boldital_font != NOFONT)
  1767.         {
  1768.         font = gui.boldital_font;
  1769.         hl_mask_todo &= ~(HL_BOLD | HL_STANDOUT | HL_ITALIC);
  1770.         }
  1771.         else if (gui.bold_font != NOFONT)
  1772.         {
  1773.         font = gui.bold_font;
  1774.         hl_mask_todo &= ~(HL_BOLD | HL_STANDOUT);
  1775.         }
  1776.         else
  1777.         font = gui.norm_font;
  1778.     }
  1779.     else if ((hl_mask_todo & HL_ITALIC) && gui.ital_font != NOFONT)
  1780.     {
  1781.         font = gui.ital_font;
  1782.         hl_mask_todo &= ~HL_ITALIC;
  1783.     }
  1784.     else
  1785.         font = gui.norm_font;
  1786.     }
  1787. # ifdef FEAT_XFONTSET
  1788.     if (fontset != NOFONTSET)
  1789.     gui_mch_set_fontset(fontset);
  1790.     else
  1791. # endif
  1792.     gui_mch_set_font(font);
  1793. #endif
  1794.  
  1795.     draw_flags = 0;
  1796.  
  1797.     /* Set the color */
  1798.     bg_color = gui.back_pixel;
  1799.     if ((flags & GUI_MON_IS_CURSOR) && gui.in_focus)
  1800.     {
  1801.     draw_flags |= DRAW_CURSOR;
  1802.     fg_color = fg;
  1803.     bg_color = bg;
  1804.     }
  1805.     else if (aep != NULL)
  1806.     {
  1807.     fg_color = aep->ae_u.gui.fg_color;
  1808.     if (fg_color == 0)
  1809.         fg_color = gui.norm_pixel;
  1810.     else
  1811.         --fg_color;
  1812.     bg_color = aep->ae_u.gui.bg_color;
  1813.     if (bg_color == 0)
  1814.         bg_color = gui.back_pixel;
  1815.     else
  1816.         --bg_color;
  1817.     }
  1818.     else
  1819.     fg_color = gui.norm_pixel;
  1820.  
  1821.     if (highlight_mask & (HL_INVERSE | HL_STANDOUT))
  1822.     {
  1823. #if defined(AMIGA) || defined(RISCOS)
  1824.     gui_mch_set_colors(bg_color, fg_color);
  1825. #else
  1826.     gui_mch_set_fg_color(bg_color);
  1827.     gui_mch_set_bg_color(fg_color);
  1828. #endif
  1829.     }
  1830.     else
  1831.     {
  1832. #if defined(AMIGA) || defined(RISCOS)
  1833.     gui_mch_set_colors(fg_color, bg_color);
  1834. #else
  1835.     gui_mch_set_fg_color(fg_color);
  1836.     gui_mch_set_bg_color(bg_color);
  1837. #endif
  1838.     }
  1839.  
  1840.     /* Clear the selection if we are about to write over it */
  1841.     if (!(flags & GUI_MON_NOCLEAR))
  1842.     clip_may_clear_selection(gui.row, gui.row);
  1843.  
  1844.  
  1845. #ifndef MSWIN16_FASTTEXT
  1846.     /* If there's no bold font, then fake it */
  1847.     if (hl_mask_todo & (HL_BOLD | HL_STANDOUT))
  1848.     draw_flags |= DRAW_BOLD;
  1849. #endif
  1850.  
  1851.     /*
  1852.      * When drawing bold or italic characters the spill-over from the left
  1853.      * neighbor may be destroyed.  Backup to start redrawing just after a
  1854.      * blank.
  1855.      */
  1856.     if ((draw_flags & DRAW_BOLD) || (highlight_mask & HL_ITALIC))
  1857.     {
  1858.     s -= back;
  1859.     len += back;
  1860.     col -= back;
  1861.     }
  1862.  
  1863. #ifdef RISCOS
  1864.     /* If there's no italic font, then fake it */
  1865.     if (hl_mask_todo & HL_ITALIC)
  1866.     draw_flags |= DRAW_ITALIC;
  1867.  
  1868.     /* Do we underline the text? */
  1869.     if (hl_mask_todo & HL_UNDERLINE)
  1870.     draw_flags |= DRAW_UNDERL;
  1871. #else
  1872.     /* Do we underline the text? */
  1873.     if ((hl_mask_todo & HL_UNDERLINE)
  1874. # ifndef MSWIN16_FASTTEXT
  1875.         || (hl_mask_todo & HL_ITALIC)
  1876. # endif
  1877.        )
  1878.     draw_flags |= DRAW_UNDERL;
  1879. #endif
  1880.  
  1881.     /* Do we draw transparantly? */
  1882.     if (flags & GUI_MON_TRS_CURSOR)
  1883.     draw_flags |= DRAW_TRANSP;
  1884.  
  1885.     /*
  1886.      * Draw the text.
  1887.      */
  1888. #ifdef FEAT_MBYTE
  1889.     if (enc_utf8)
  1890.     {
  1891.     int    start;        /* index of bytes to be drawn */
  1892.     int    cells;        /* cellwidth of bytes to be drawn */
  1893.     int    thislen;    /* length of bytes to be drawin */
  1894.     int    cn;        /* cellwidth of current char */
  1895.     int    i;        /* index of current char */
  1896.     int    c;        /* current char value */
  1897.     int    cl;        /* byte length of current char */
  1898.     int    comping;    /* current char is composing */
  1899.     int    scol = col;    /* screen column */
  1900.     int    dowide;        /* use 'guifontwide' */
  1901.  
  1902.     /* Break the string at a composing character, it has to be drawn on
  1903.      * top of the previous character. */
  1904.     start = 0;
  1905.     cells = 0;
  1906.     for (i = 0; i < len; i += cl)
  1907.     {
  1908.         c = utf_ptr2char(s + i);
  1909.         cn = utf_char2cells(c);
  1910.         if (cn > 1
  1911. # ifdef FEAT_XFONTSET
  1912.             && fontset == NOFONTSET
  1913. # endif
  1914.             && gui.wide_font != NOFONT)
  1915.         dowide = TRUE;
  1916.         else
  1917.         dowide = FALSE;
  1918.         comping = utf_iscomposing(c);
  1919.         if (!comping)    /* count cells from non-composing chars */
  1920.         cells += cn;
  1921.         cl = utf_ptr2len_check(s + i);
  1922.         if (cl == 0)    /* hit end of string */
  1923.         len = i + cl;    /* len must be wrong "cannot happen" */
  1924.  
  1925.         /* print the string so far if it's the last character or there is
  1926.          * a composing character. */
  1927.         if (i + cl >= len || (comping && i > start)
  1928. #if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
  1929.             || (cn > 1
  1930. # ifdef FEAT_XFONTSET
  1931.             /* No fontset: At least draw char after wide char at
  1932.              * right position. */
  1933.             && fontset == NOFONTSET
  1934. # endif
  1935.                )
  1936. #endif
  1937.            )
  1938.         {
  1939.         if (comping || dowide)
  1940.             thislen = i - start;
  1941.         else
  1942.             thislen = i - start + cl;
  1943.         if (thislen > 0)
  1944.         {
  1945.             gui_mch_draw_string(gui.row, scol, s + start, thislen,
  1946.                                   draw_flags);
  1947.             start += thislen;
  1948.         }
  1949.         scol += cells;
  1950.         cells = 0;
  1951.         if (dowide)
  1952.         {
  1953.             gui_mch_set_font(gui.wide_font);
  1954.             gui_mch_draw_string(gui.row, scol - cn,
  1955.                            s + start, cl, draw_flags);
  1956.             gui_mch_set_font(font);
  1957.             start += cl;
  1958.         }
  1959.  
  1960. #if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
  1961.         /* No fontset: draw a space to fill the gap after a wide char */
  1962.         if (cn > 1 && (draw_flags & DRAW_TRANSP) == 0
  1963. # ifdef FEAT_XFONTSET
  1964.             && fontset == NOFONTSET
  1965. # endif
  1966.             && !dowide)
  1967.             gui_mch_draw_string(gui.row, scol - 1, (char_u *)" ",
  1968.                                    1, draw_flags);
  1969. #endif
  1970.         }
  1971.         /* Draw a composing char on top of the previous char. */
  1972.         if (comping)
  1973.         {
  1974.         gui_mch_draw_string(gui.row, scol - cn, s + i, cl,
  1975.                             draw_flags | DRAW_TRANSP);
  1976.         start = i + cl;
  1977.         }
  1978.     }
  1979.     /* The stuff below assumes "len" is the length in screen columns. */
  1980.     len = scol - col;
  1981.     }
  1982.     else
  1983. #endif
  1984.     {
  1985.     gui_mch_draw_string(gui.row, col, s, len, draw_flags);
  1986. #ifdef FEAT_MBYTE
  1987.     if (enc_dbcs == DBCS_JPNU)
  1988.     {
  1989.         int        clen = 0;
  1990.         int        i;
  1991.  
  1992.         /* Get the length in display cells, this can be different from the
  1993.          * number of bytes for "euc-jp". */
  1994.         for (i = 0; i < len; i += (*mb_ptr2len_check)(s + i))
  1995.         clen += (*mb_ptr2cells)(s + i);
  1996.         len = clen;
  1997.     }
  1998. #endif
  1999.     }
  2000.  
  2001.     if (!(flags & (GUI_MON_IS_CURSOR | GUI_MON_TRS_CURSOR)))
  2002.     gui.col = col + len;
  2003.  
  2004.     /* May need to invert it when it's part of the selection. */
  2005.     if (flags & GUI_MON_NOCLEAR)
  2006.     clip_may_redraw_selection(gui.row, col, len);
  2007.  
  2008.     if (!(flags & (GUI_MON_IS_CURSOR | GUI_MON_TRS_CURSOR)))
  2009.     {
  2010.     /* Invalidate the old physical cursor position if we wrote over it */
  2011.     if (gui.cursor_row == gui.row
  2012.         && gui.cursor_col >= col
  2013.         && gui.cursor_col < col + len)
  2014.         gui.cursor_is_valid = FALSE;
  2015.     }
  2016.  
  2017. #ifdef FEAT_SIGN_ICONS
  2018.     if (draw_sign)
  2019.     /* Draw the sign on top of the spaces. */
  2020.     gui_mch_drawsign(gui.row, col, gui.highlight_mask);
  2021. #endif
  2022. }
  2023.  
  2024. /*
  2025.  * Un-draw the cursor.    Actually this just redraws the character at the given
  2026.  * position.  The character just before it too, for when it was in bold.
  2027.  */
  2028.     void
  2029. gui_undraw_cursor()
  2030. {
  2031.     if (gui.cursor_is_valid)
  2032.     {
  2033. #ifdef FEAT_HANGULIN
  2034.     if (composing_hangul
  2035.             && gui.col == gui.cursor_col && gui.row == gui.cursor_row)
  2036.         gui_outstr_nowrap(composing_hangul_buffer, 2,
  2037.             GUI_MON_IS_CURSOR | GUI_MON_NOCLEAR,
  2038.             gui.norm_pixel, gui.back_pixel, 0);
  2039.     else
  2040.     {
  2041. #endif
  2042.     if (gui_redraw_block(gui.cursor_row, gui.cursor_col,
  2043.                   gui.cursor_row, gui.cursor_col, GUI_MON_NOCLEAR)
  2044.         && gui.cursor_col > 0)
  2045.         (void)gui_redraw_block(gui.cursor_row, gui.cursor_col - 1,
  2046.              gui.cursor_row, gui.cursor_col - 1, GUI_MON_NOCLEAR);
  2047. #ifdef FEAT_HANGULIN
  2048.         if (composing_hangul)
  2049.         (void)gui_redraw_block(gui.cursor_row, gui.cursor_col + 1,
  2050.             gui.cursor_row, gui.cursor_col + 1, GUI_MON_NOCLEAR);
  2051.     }
  2052. #endif
  2053.     }
  2054. }
  2055.  
  2056.     void
  2057. gui_redraw(x, y, w, h)
  2058.     int        x;
  2059.     int        y;
  2060.     int        w;
  2061.     int        h;
  2062. {
  2063.     int        row1, col1, row2, col2;
  2064.  
  2065.     row1 = Y_2_ROW(y);
  2066.     col1 = X_2_COL(x);
  2067.     row2 = Y_2_ROW(y + h - 1);
  2068.     col2 = X_2_COL(x + w - 1);
  2069.  
  2070.     (void)gui_redraw_block(row1, col1, row2, col2, GUI_MON_NOCLEAR);
  2071.  
  2072.     /*
  2073.      * We may need to redraw the cursor, but don't take it upon us to change
  2074.      * its location after a scroll.
  2075.      * (maybe be more strict even and test col too?)
  2076.      * These things may be outside the update/clipping region and reality may
  2077.      * not reflect Vims internal ideas if these operations are clipped away.
  2078.      */
  2079.     if (gui.row == gui.cursor_row)
  2080.     gui_update_cursor(FALSE, TRUE);
  2081. }
  2082.  
  2083. /*
  2084.  * Draw a rectangular block of characters, from row1 to row2 (inclusive) and
  2085.  * from col1 to col2 (inclusive).
  2086.  * Return TRUE when the character before the first drawn character has
  2087.  * different attributes (may have to be redrawn too).
  2088.  */
  2089.     int
  2090. gui_redraw_block(row1, col1, row2, col2, flags)
  2091.     int        row1;
  2092.     int        col1;
  2093.     int        row2;
  2094.     int        col2;
  2095.     int        flags;    /* flags for gui_outstr_nowrap() */
  2096. {
  2097.     int        old_row, old_col;
  2098.     long_u    old_hl_mask;
  2099.     int        off;
  2100.     char_u    first_attr;
  2101.     int        idx, len;
  2102.     int        back;
  2103.     int        retval = FALSE;
  2104. #ifdef FEAT_MBYTE
  2105.     int        orig_col1, orig_col2;
  2106. #endif
  2107.  
  2108.     /* Don't try to update when ScreenLines is not valid */
  2109.     if (!screen_cleared || ScreenLines == NULL)
  2110.     return retval;
  2111.  
  2112.     /* Don't try to draw outside the shell! */
  2113.     /* Check everything, strange values may be caused by a big border width */
  2114.     col1 = check_col(col1);
  2115.     col2 = check_col(col2);
  2116.     row1 = check_row(row1);
  2117.     row2 = check_row(row2);
  2118.  
  2119.     /* Remember where our cursor was */
  2120.     old_row = gui.row;
  2121.     old_col = gui.col;
  2122.     old_hl_mask = gui.highlight_mask;
  2123. #ifdef FEAT_MBYTE
  2124.     orig_col1 = col1;
  2125.     orig_col2 = col2;
  2126. #endif
  2127.  
  2128.     for (gui.row = row1; gui.row <= row2; gui.row++)
  2129.     {
  2130. #ifdef FEAT_MBYTE
  2131.     /* When only half of a double-wide character is in the block, include
  2132.      * the other half. */
  2133.     col1 = orig_col1;
  2134.     col2 = orig_col2;
  2135.     off = LineOffset[gui.row];
  2136.     if (enc_dbcs != 0)
  2137.     {
  2138.         if (col1 > 0)
  2139.         col1 -= dbcs_screen_head_off(ScreenLines + off,
  2140.                             ScreenLines + off + col1);
  2141.         col2 += dbcs_screen_tail_off(ScreenLines + off,
  2142.                             ScreenLines + off + col2);
  2143.     }
  2144.     else if (enc_utf8)
  2145.     {
  2146.         if (ScreenLines[off + col1] == 0)
  2147.         --col1;
  2148.     }
  2149. #endif
  2150.     gui.col = col1;
  2151.     off = LineOffset[gui.row] + gui.col;
  2152.     len = col2 - col1 + 1;
  2153.  
  2154.     /* Find how many chars back this highlighting starts, or where a space
  2155.      * is.  Needed for when the bold trick is used */
  2156.     for (back = 0; back < col1; ++back)
  2157.         if (ScreenAttrs[off - 1 - back] != ScreenAttrs[off]
  2158.             || ScreenLines[off - 1 - back] == ' ')
  2159.         break;
  2160.     retval = (col1 > 0 && ScreenAttrs[off - 1] != 0 && back == 0);
  2161.  
  2162.     /* break it up in strings of characters with the same attributes */
  2163.     /* print UTF-8 characters individually */
  2164.     while (len > 0)
  2165.     {
  2166.         first_attr = ScreenAttrs[off];
  2167.         gui.highlight_mask = first_attr;
  2168. #ifdef FEAT_MBYTE
  2169.         if (enc_utf8 && ScreenLinesUC[off] != 0)
  2170.         {
  2171.         /* output multi-byte character separately */
  2172.         gui_screenchar(off, flags, (guicolor_T)0, (guicolor_T)0, back);
  2173.         ++off;
  2174.         --len;
  2175.         if (ScreenLines[off] == 0)
  2176.         {
  2177.             ++off;
  2178.             --len;
  2179.         }
  2180.         }
  2181.         else if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
  2182.         {
  2183.         /* output double-byte, single-width character separately */
  2184.         gui_screenchar(off, flags, (guicolor_T)0, (guicolor_T)0, back);
  2185.         ++off;
  2186.         --len;
  2187.         }
  2188.         else
  2189. #endif
  2190.         {
  2191.         for (idx = 0; len > 0 && ScreenAttrs[off + idx] == first_attr;
  2192.                                     idx++)
  2193.         {
  2194. #ifdef FEAT_MBYTE
  2195.             /* Stop at a multi-byte Unicode character. */
  2196.             if (enc_utf8 && ScreenLinesUC[off + idx] != 0)
  2197.             break;
  2198.             if (enc_dbcs == DBCS_JPNU)
  2199.             {
  2200.             /* Stop at a double-byte single-width char. */
  2201.             if (ScreenLines[off + idx] == 0x8e)
  2202.                 break;
  2203.             if (len > 1 && (*mb_ptr2len_check)(ScreenLines
  2204.                                 + off + idx) == 2)
  2205.             {
  2206.                 ++idx;  /* skip second byte of double-byte char */
  2207.                 --len;
  2208.             }
  2209.             }
  2210. #endif
  2211.             --len;
  2212.         }
  2213.         gui_outstr_nowrap(ScreenLines + off, idx, flags,
  2214.                       (guicolor_T)0, (guicolor_T)0, back);
  2215.         off += idx;
  2216.         }
  2217.         back = 0;
  2218.     }
  2219.     }
  2220.  
  2221.     /* Put the cursor back where it was */
  2222.     gui.row = old_row;
  2223.     gui.col = old_col;
  2224.     gui.highlight_mask = old_hl_mask;
  2225.  
  2226.     return retval;
  2227. }
  2228.  
  2229.     static void
  2230. gui_delete_lines(row, count)
  2231.     int        row;
  2232.     int        count;
  2233. {
  2234.     if (count <= 0)
  2235.     return;
  2236.  
  2237.     if (row + count > gui.scroll_region_bot)
  2238.     /* Scrolled out of region, just blank the lines out */
  2239.     gui_clear_block(row, gui.scroll_region_left,
  2240.                   gui.scroll_region_bot, gui.scroll_region_right);
  2241.     else
  2242.     {
  2243.     gui_mch_delete_lines(row, count);
  2244.  
  2245.     /* If the cursor was in the deleted lines it's now gone.  If the
  2246.      * cursor was in the scrolled lines adjust its position. */
  2247.     if (gui.cursor_row >= row
  2248.         && gui.cursor_col >= gui.scroll_region_left
  2249.         && gui.cursor_col <= gui.scroll_region_right)
  2250.     {
  2251.         if (gui.cursor_row < row + count)
  2252.         gui.cursor_is_valid = FALSE;
  2253.         else if (gui.cursor_row <= gui.scroll_region_bot)
  2254.         gui.cursor_row -= count;
  2255.     }
  2256.     }
  2257. }
  2258.  
  2259.     static void
  2260. gui_insert_lines(row, count)
  2261.     int        row;
  2262.     int        count;
  2263. {
  2264.     if (count <= 0)
  2265.     return;
  2266.  
  2267.     if (row + count > gui.scroll_region_bot)
  2268.     /* Scrolled out of region, just blank the lines out */
  2269.     gui_clear_block(row, gui.scroll_region_left,
  2270.                   gui.scroll_region_bot, gui.scroll_region_right);
  2271.     else
  2272.     {
  2273.     gui_mch_insert_lines(row, count);
  2274.  
  2275.     if (gui.cursor_row >= gui.row
  2276.         && gui.cursor_col >= gui.scroll_region_left
  2277.         && gui.cursor_col <= gui.scroll_region_right)
  2278.     {
  2279.         if (gui.cursor_row <= gui.scroll_region_bot - count)
  2280.         gui.cursor_row += count;
  2281.         else if (gui.cursor_row <= gui.scroll_region_bot)
  2282.         gui.cursor_is_valid = FALSE;
  2283.     }
  2284.     }
  2285. }
  2286.  
  2287. /*
  2288.  * The main GUI input routine.    Waits for a character from the keyboard.
  2289.  * wtime == -1        Wait forever.
  2290.  * wtime == 0        Don't wait.
  2291.  * wtime > 0        Wait wtime milliseconds for a character.
  2292.  * Returns OK if a character was found to be available within the given time,
  2293.  * or FAIL otherwise.
  2294.  */
  2295.     int
  2296. gui_wait_for_chars(wtime)
  2297.     long    wtime;
  2298. {
  2299.     int        retval;
  2300. #ifdef FEAT_AUTOCMD
  2301.     static int once_already = 0;
  2302. #endif
  2303.  
  2304.     /*
  2305.      * If we're going to wait a bit, update the menus and mouse shape for the
  2306.      * current State.
  2307.      */
  2308.     if (wtime != 0)
  2309.     {
  2310. #ifdef FEAT_MENU
  2311.     gui_update_menus(0);
  2312. #endif
  2313.     }
  2314.  
  2315.     gui_mch_update();
  2316.     if (!vim_is_input_buf_empty())    /* Got char, return immediately */
  2317.     {
  2318. #ifdef FEAT_AUTOCMD
  2319.     once_already = 0;
  2320. #endif
  2321.     return OK;
  2322.     }
  2323.     if (wtime == 0)    /* Don't wait for char */
  2324.     {
  2325. #ifdef FEAT_AUTOCMD
  2326.     once_already = 0;
  2327. #endif
  2328.     return FAIL;
  2329.     }
  2330.  
  2331.     /* Before waiting, flush any output to the screen. */
  2332.     gui_mch_flush();
  2333.  
  2334.     if (wtime > 0)
  2335.     {
  2336.     /* Blink when waiting for a character.    Probably only does something
  2337.      * for showmatch() */
  2338.     gui_mch_start_blink();
  2339.     retval = gui_mch_wait_for_chars(wtime);
  2340.     gui_mch_stop_blink();
  2341. #ifdef FEAT_AUTOCMD
  2342.     once_already = 0;
  2343. #endif
  2344.     return retval;
  2345.     }
  2346.  
  2347.     /*
  2348.      * While we are waiting indefenitely for a character, blink the cursor.
  2349.      */
  2350.     gui_mch_start_blink();
  2351.  
  2352.  
  2353. #ifdef FEAT_AUTOCMD
  2354.     /* If there is no character available within 2 seconds (default),
  2355.      * write the autoscript file to disk */
  2356.     if (once_already == 2)
  2357.     {
  2358.     updatescript(0);
  2359.     retval = gui_mch_wait_for_chars(-1L);
  2360.     once_already = 0;
  2361.     }
  2362.     else if (once_already == 1)
  2363.     {
  2364.     setcursor();
  2365.     once_already = 2;
  2366.     retval = 0;
  2367.     }
  2368.     else
  2369. #endif
  2370.     if (gui_mch_wait_for_chars(p_ut) != OK)
  2371.     {
  2372. #ifdef FEAT_AUTOCMD
  2373.     if (has_cursorhold() && get_real_state() == NORMAL_BUSY)
  2374.     {
  2375.         apply_autocmds(EVENT_CURSORHOLD, NULL, NULL, FALSE, curbuf);
  2376.         update_screen(VALID);
  2377.  
  2378.         once_already = 1;
  2379.         retval = 0;
  2380.     }
  2381.     else
  2382. #endif
  2383.     {
  2384.         updatescript(0);
  2385.         retval = gui_mch_wait_for_chars(-1L);
  2386. #ifdef FEAT_AUTOCMD
  2387.         once_already = 0;
  2388. #endif
  2389.     }
  2390.     }
  2391.     else
  2392.     retval = OK;
  2393.  
  2394.     gui_mch_stop_blink();
  2395.     return retval;
  2396. }
  2397.  
  2398. /*
  2399.  * Generic mouse support function.  Add a mouse event to the input buffer with
  2400.  * the given properties.
  2401.  *  button        --- may be any of MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT,
  2402.  *            MOUSE_DRAG, or MOUSE_RELEASE.
  2403.  *            MOUSE_4 and MOUSE_5 are used for a scroll wheel.
  2404.  *  x, y        --- Coordinates of mouse in pixels.
  2405.  *  repeated_click  --- TRUE if this click comes only a short time after a
  2406.  *            previous click.
  2407.  *  modifiers        --- Bit field which may be any of the following modifiers
  2408.  *            or'ed together: MOUSE_SHIFT | MOUSE_CTRL | MOUSE_ALT.
  2409.  * This function will ignore drag events where the mouse has not moved to a new
  2410.  * character.
  2411.  */
  2412.     void
  2413. gui_send_mouse_event(button, x, y, repeated_click, modifiers)
  2414.     int        button;
  2415.     int        x;
  2416.     int        y;
  2417.     int        repeated_click;
  2418.     int_u   modifiers;
  2419. {
  2420.     static int        prev_row = 0, prev_col = 0;
  2421.     static int        prev_button = -1;
  2422.     static int        num_clicks = 1;
  2423.     char_u        string[6];
  2424.     int            row, col;
  2425. #ifdef FEAT_CLIPBOARD
  2426.     int            checkfor;
  2427.     int            did_clip = FALSE;
  2428. #endif
  2429.  
  2430.     /*
  2431.      * Scrolling may happen at any time, also while a selection is present.
  2432.      */
  2433.     if (button == MOUSE_4 || button == MOUSE_5)
  2434.     {
  2435.     /* Don't put events in the input queue now. */
  2436.     if (hold_gui_events)
  2437.         return;
  2438.  
  2439.     string[3] = CSI;
  2440.     string[4] = KS_EXTRA;
  2441.     string[5] = (int)(button == MOUSE_4 ? KE_MOUSEDOWN : KE_MOUSEUP);
  2442.     if (modifiers == 0)
  2443.         add_to_input_buf(string + 3, 3);
  2444.     else
  2445.     {
  2446.         string[0] = CSI;
  2447.         string[1] = KS_MODIFIER;
  2448.         string[2] = 0;
  2449.         if (modifiers & MOUSE_SHIFT)
  2450.         string[2] |= MOD_MASK_SHIFT;
  2451.         if (modifiers & MOUSE_CTRL)
  2452.         string[2] |= MOD_MASK_CTRL;
  2453.         if (modifiers & MOUSE_ALT)
  2454.         string[2] |= MOD_MASK_ALT;
  2455.         add_to_input_buf(string, 6);
  2456.     }
  2457.     return;
  2458.     }
  2459.  
  2460. #ifdef FEAT_CLIPBOARD
  2461.     /* If a clipboard selection is in progress, handle it */
  2462.     if (clip_star.state == SELECT_IN_PROGRESS)
  2463.     {
  2464.     clip_process_selection(button, X_2_COL(x), Y_2_ROW(y), repeated_click);
  2465.     return;
  2466.     }
  2467.  
  2468.     /* Determine which mouse settings to look for based on the current mode */
  2469.     switch (get_real_state())
  2470.     {
  2471.     case NORMAL_BUSY:
  2472.     case OP_PENDING:
  2473.     case NORMAL:        checkfor = MOUSE_NORMAL;    break;
  2474.     case VISUAL:        checkfor = MOUSE_VISUAL;    break;
  2475.     case REPLACE:
  2476.     case REPLACE+LANGMAP:
  2477. #ifdef FEAT_VREPLACE
  2478.     case VREPLACE:
  2479.     case VREPLACE+LANGMAP:
  2480. #endif
  2481.     case INSERT:
  2482.     case INSERT+LANGMAP:    checkfor = MOUSE_INSERT;    break;
  2483.     case HITRETURN:        checkfor = MOUSE_RETURN;    break;
  2484.  
  2485.         /*
  2486.          * On the command line, use the clipboard selection on all lines
  2487.          * but the command line.  But not when pasting.
  2488.          */
  2489.     case CMDLINE:
  2490.     case CMDLINE+LANGMAP:
  2491.         if (Y_2_ROW(y) < cmdline_row && button != MOUSE_MIDDLE)
  2492.         checkfor = MOUSE_NONE;
  2493.         else
  2494.         checkfor = MOUSE_COMMAND;
  2495.         break;
  2496.  
  2497.     default:
  2498.         checkfor = MOUSE_NONE;
  2499.         break;
  2500.     };
  2501.  
  2502.     /*
  2503.      * Allow clipboard selection of text on the command line in "normal"
  2504.      * modes.  Don't do this when dragging the status line, or extending a
  2505.      * Visual selection.
  2506.      */
  2507.     if ((State == NORMAL || State == NORMAL_BUSY || (State & INSERT))
  2508.         && Y_2_ROW(y) >= topframe->fr_height
  2509.         && button != MOUSE_DRAG
  2510. # ifdef FEAT_MOUSESHAPE
  2511.         && !drag_status_line
  2512. #  ifdef FEAT_VERTSPLIT
  2513.         && !drag_sep_line
  2514. #  endif
  2515. # endif
  2516.         )
  2517.     checkfor = MOUSE_NONE;
  2518.  
  2519.     /*
  2520.      * Use modeless selection when holding CTRL and SHIFT pressed.
  2521.      */
  2522.     if ((modifiers & MOUSE_CTRL) && (modifiers & MOUSE_SHIFT))
  2523.     checkfor = MOUSE_NONEF;
  2524.  
  2525.     /*
  2526.      * In Ex mode, always use modeless selection.
  2527.      */
  2528.     if (exmode_active)
  2529.     checkfor = MOUSE_NONE;
  2530.  
  2531.     /*
  2532.      * If the mouse settings say to not use the mouse, use the modeless
  2533.      * selection.  But if Visual is active, assume that only the Visual area
  2534.      * will be selected.
  2535.      * Exception: On the command line, both the selection is used and a mouse
  2536.      * key is send.
  2537.      */
  2538.     if (!mouse_has(checkfor) || checkfor == MOUSE_COMMAND)
  2539.     {
  2540. #ifdef FEAT_VISUAL
  2541.     /* Don't do modeless selection in Visual mode. */
  2542.     if (checkfor != MOUSE_NONEF && VIsual_active)
  2543.         return;
  2544. #endif
  2545.  
  2546.     /*
  2547.      * When 'mousemodel' is "popup", shift-left is translated to right.
  2548.      * But not when also using Ctrl.
  2549.      */
  2550.     if (mouse_model_popup() && button == MOUSE_LEFT
  2551.         && (modifiers & MOUSE_SHIFT) && !(modifiers & MOUSE_CTRL))
  2552.     {
  2553.         button = MOUSE_RIGHT;
  2554.         modifiers &= ~ MOUSE_SHIFT;
  2555.     }
  2556.  
  2557.     /* If the selection is done, allow the right button to extend it.
  2558.      * If the selection is cleared, allow the right button to start it
  2559.      * from the cursor position. */
  2560.     if (button == MOUSE_RIGHT)
  2561.     {
  2562.         if (clip_star.state == SELECT_CLEARED)
  2563.         {
  2564.         if (State & CMDLINE)
  2565.         {
  2566.             col = msg_col;
  2567.             row = msg_row;
  2568.         }
  2569.         else
  2570.         {
  2571.             col = curwin->w_wcol;
  2572.             row = curwin->w_wrow + W_WINROW(curwin);
  2573.         }
  2574.         clip_start_selection(col, row, FALSE);
  2575.         }
  2576.         clip_process_selection(button, X_2_COL(x), Y_2_ROW(y),
  2577.                                   repeated_click);
  2578.         did_clip = TRUE;
  2579.     }
  2580.     /* Allow the left button to start the selection */
  2581.     else if (button ==
  2582. # ifdef RISCOS
  2583.         /* Only start a drag on a drag event. Otherwise
  2584.          * we don't get a release event.
  2585.          */
  2586.             MOUSE_DRAG
  2587. # else
  2588.             MOUSE_LEFT
  2589. # endif
  2590.                 )
  2591.     {
  2592.         clip_start_selection(X_2_COL(x), Y_2_ROW(y), repeated_click);
  2593.         did_clip = TRUE;
  2594.     }
  2595. # ifdef RISCOS
  2596.     else if (button == MOUSE_LEFT)
  2597.     {
  2598.         clip_clear_selection();
  2599.         did_clip = TRUE;
  2600.     }
  2601. # endif
  2602.  
  2603.     /* Always allow pasting */
  2604.     if (button != MOUSE_MIDDLE)
  2605.     {
  2606.         if (!mouse_has(checkfor) || button == MOUSE_RELEASE)
  2607.         return;
  2608.         if (checkfor != MOUSE_COMMAND)
  2609.         button = MOUSE_LEFT;
  2610.     }
  2611.     repeated_click = FALSE;
  2612.     }
  2613.  
  2614.     if (clip_star.state != SELECT_CLEARED && !did_clip)
  2615.     clip_clear_selection();
  2616. #endif
  2617.  
  2618.     /* Don't put events in the input queue now. */
  2619.     if (hold_gui_events)
  2620.     return;
  2621.  
  2622.     row = gui_xy2colrow(x, y, &col);
  2623.  
  2624.     /*
  2625.      * If we are dragging and the mouse hasn't moved far enough to be on a
  2626.      * different character, then don't send an event to vim.
  2627.      */
  2628.     if (button == MOUSE_DRAG)
  2629.     {
  2630.     if (row == prev_row && col == prev_col)
  2631.         return;
  2632.     /* Dragging above the window, set "row" to -1 to cause a scroll. */
  2633.     if (y < 0)
  2634.         row = -1;
  2635.     }
  2636.  
  2637.     /*
  2638.      * If topline has changed (window scrolled) since the last click, reset
  2639.      * repeated_click, because we don't want starting Visual mode when
  2640.      * clicking on a different character in the text.
  2641.      */
  2642.     if (curwin->w_topline != gui_prev_topline
  2643. #ifdef FEAT_DIFF
  2644.         || curwin->w_topfill != gui_prev_topfill
  2645. #endif
  2646.         )
  2647.     repeated_click = FALSE;
  2648.  
  2649.     string[0] = CSI;    /* this sequence is recognized by check_termcode() */
  2650.     string[1] = KS_MOUSE;
  2651.     string[2] = KE_FILLER;
  2652.     if (button != MOUSE_DRAG && button != MOUSE_RELEASE)
  2653.     {
  2654.     if (repeated_click)
  2655.     {
  2656.         /*
  2657.          * Handle multiple clicks.    They only count if the mouse is still
  2658.          * pointing at the same character.
  2659.          */
  2660.         if (button != prev_button || row != prev_row || col != prev_col)
  2661.         num_clicks = 1;
  2662.         else if (++num_clicks > 4)
  2663.         num_clicks = 1;
  2664.     }
  2665.     else
  2666.         num_clicks = 1;
  2667.     prev_button = button;
  2668.     gui_prev_topline = curwin->w_topline;
  2669. #ifdef FEAT_DIFF
  2670.     gui_prev_topfill = curwin->w_topfill;
  2671. #endif
  2672.  
  2673.     string[3] = (char_u)(button | 0x20);
  2674.     SET_NUM_MOUSE_CLICKS(string[3], num_clicks);
  2675.     }
  2676.     else
  2677.     string[3] = (char_u)button;
  2678.  
  2679.     string[3] |= modifiers;
  2680.     /* Can't encode numbers above 222... */
  2681.     string[4] = (char_u)((col > 222 ? 222 : col) + ' ' + 1);
  2682.     string[5] = (char_u)((row > 222 ? 222 : row) + ' ' + 1);
  2683.     add_to_input_buf(string, 6);
  2684.  
  2685.     if (row < 0)
  2686.     prev_row = 0;
  2687.     else
  2688.     prev_row = row;
  2689.     prev_col = col;
  2690.  
  2691.     /*
  2692.      * We need to make sure this is cleared since Athena doesn't tell us when
  2693.      * he is done dragging.
  2694.      */
  2695. #ifdef FEAT_GUI_ATHENA
  2696.     gui.dragged_sb = SBAR_NONE;
  2697. #endif
  2698. }
  2699.  
  2700. /*
  2701.  * Convert x and y coordinate to column and row in text window.
  2702.  * Corrects for multi-byte character.
  2703.  * returns column in "*colp" and row as return value;
  2704.  */
  2705.     int
  2706. gui_xy2colrow(x, y, colp)
  2707.     int        x;
  2708.     int        y;
  2709.     int        *colp;
  2710. {
  2711.     int        col = check_col(X_2_COL(x));
  2712.     int        row = check_row(Y_2_ROW(y));
  2713.  
  2714. #ifdef FEAT_MBYTE
  2715.     *colp = mb_fix_col(col, row);
  2716. #else
  2717.     *colp = col;
  2718. #endif
  2719.     return row;
  2720. }
  2721.  
  2722. #if defined(FEAT_MENU) || defined(PROTO)
  2723. /*
  2724.  * Callback function for when a menu entry has been selected.
  2725.  */
  2726.     void
  2727. gui_menu_cb(menu)
  2728.     vimmenu_T *menu;
  2729. {
  2730.     char_u  bytes[3 + sizeof(long_u)];
  2731.  
  2732.     /* Don't put events in the input queue now. */
  2733.     if (hold_gui_events)
  2734.     return;
  2735.  
  2736.     bytes[0] = CSI;
  2737.     bytes[1] = KS_MENU;
  2738.     bytes[2] = KE_FILLER;
  2739.     add_long_to_buf((long_u)menu, bytes + 3);
  2740.     add_to_input_buf(bytes, 3 + sizeof(long_u));
  2741. }
  2742. #endif
  2743.  
  2744. /*
  2745.  * Set which components are present.
  2746.  * If "oldval" is not NULL, "oldval" is the previous value, the new * value is
  2747.  * in p_go.
  2748.  */
  2749. /*ARGSUSED*/
  2750.     void
  2751. gui_init_which_components(oldval)
  2752.     char_u    *oldval;
  2753. {
  2754.     static int    prev_which_scrollbars[3] = {-1, -1, -1};
  2755. #ifdef FEAT_MENU
  2756.     static int    prev_menu_is_active = -1;
  2757. #endif
  2758. #ifdef FEAT_TOOLBAR
  2759.     static int    prev_toolbar = -1;
  2760.     int        using_toolbar = FALSE;
  2761. #endif
  2762. #ifdef FEAT_FOOTER
  2763.     static int    prev_footer = -1;
  2764.     int        using_footer = FALSE;
  2765. #endif
  2766. #if defined(FEAT_MENU) && !defined(WIN16)
  2767.     static int    prev_tearoff = -1;
  2768.     int        using_tearoff = FALSE;
  2769. #endif
  2770.  
  2771.     char_u    *p;
  2772.     int        i;
  2773. #ifdef FEAT_MENU
  2774.     int        grey_old, grey_new;
  2775.     char_u    *temp;
  2776. #endif
  2777.     win_T    *wp;
  2778.     int        need_set_size;
  2779.  
  2780. #ifdef FEAT_MENU
  2781.     if (oldval != NULL && gui.in_use)
  2782.     {
  2783.     /*
  2784.      * Check if the menu's go from grey to non-grey or vise versa.
  2785.      */
  2786.     grey_old = (vim_strchr(oldval, GO_GREY) != NULL);
  2787.     grey_new = (vim_strchr(p_go, GO_GREY) != NULL);
  2788.     if (grey_old != grey_new)
  2789.     {
  2790.         temp = p_go;
  2791.         p_go = oldval;
  2792.         gui_update_menus(MENU_ALL_MODES);
  2793.         p_go = temp;
  2794.     }
  2795.     }
  2796.     gui.menu_is_active = FALSE;
  2797. #endif
  2798.  
  2799.     for (i = 0; i < 3; i++)
  2800.     gui.which_scrollbars[i] = FALSE;
  2801.     for (p = p_go; *p; p++)
  2802.     switch (*p)
  2803.     {
  2804.         case GO_LEFT:
  2805.         gui.which_scrollbars[SBAR_LEFT] = TRUE;
  2806.         break;
  2807.         case GO_RIGHT:
  2808.         gui.which_scrollbars[SBAR_RIGHT] = TRUE;
  2809.         break;
  2810. #ifdef FEAT_VERTSPLIT
  2811.         case GO_VLEFT:
  2812.         if (win_hasvertsplit())
  2813.             gui.which_scrollbars[SBAR_LEFT] = TRUE;
  2814.         break;
  2815.         case GO_VRIGHT:
  2816.         if (win_hasvertsplit())
  2817.             gui.which_scrollbars[SBAR_RIGHT] = TRUE;
  2818.         break;
  2819. #endif
  2820.         case GO_BOT:
  2821.         gui.which_scrollbars[SBAR_BOTTOM] = TRUE;
  2822.         break;
  2823. #ifdef FEAT_MENU
  2824.         case GO_MENUS:
  2825.         gui.menu_is_active = TRUE;
  2826.         break;
  2827. #endif
  2828.         case GO_GREY:
  2829.         /* make menu's have grey items, ignored here */
  2830.         break;
  2831. #ifdef FEAT_TOOLBAR
  2832.         case GO_TOOLBAR:
  2833.         using_toolbar = TRUE;
  2834.         break;
  2835. #endif
  2836. #ifdef FEAT_FOOTER
  2837.         case GO_FOOTER:
  2838.         using_footer = TRUE;
  2839.         break;
  2840. #endif
  2841.         case GO_TEAROFF:
  2842. #if defined(FEAT_MENU) && !defined(WIN16)
  2843.         using_tearoff = TRUE;
  2844. #endif
  2845.         break;
  2846.         default:
  2847.         /* Ignore options that are not supported */
  2848.         break;
  2849.     }
  2850.     if (gui.in_use)
  2851.     {
  2852.     need_set_size = FALSE;
  2853.     for (i = 0; i < 3; i++)
  2854.     {
  2855.         if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
  2856.         {
  2857.         if (i == SBAR_BOTTOM)
  2858.             gui_mch_enable_scrollbar(&gui.bottom_sbar,
  2859.                              gui.which_scrollbars[i]);
  2860.         else
  2861.         {
  2862.             FOR_ALL_WINDOWS(wp)
  2863.             {
  2864.             gui_do_scrollbar(wp, i, gui.which_scrollbars[i]);
  2865.             }
  2866.         }
  2867.         need_set_size = TRUE;
  2868.         }
  2869.         prev_which_scrollbars[i] = gui.which_scrollbars[i];
  2870.     }
  2871.  
  2872. #ifdef FEAT_MENU
  2873.     if (gui.menu_is_active != prev_menu_is_active)
  2874.     {
  2875.         gui_mch_enable_menu(gui.menu_is_active);
  2876.         prev_menu_is_active = gui.menu_is_active;
  2877.         need_set_size = TRUE;
  2878.     }
  2879. #endif
  2880.  
  2881. #ifdef FEAT_TOOLBAR
  2882.     if (using_toolbar != prev_toolbar)
  2883.     {
  2884.         gui_mch_show_toolbar(using_toolbar);
  2885.         prev_toolbar = using_toolbar;
  2886.         need_set_size = TRUE;
  2887.     }
  2888. #endif
  2889. #ifdef FEAT_FOOTER
  2890.     if (using_footer != prev_footer)
  2891.     {
  2892.         gui_mch_enable_footer(using_footer);
  2893.         prev_footer = using_footer;
  2894.         need_set_size = TRUE;
  2895.     }
  2896. #endif
  2897. #if defined(FEAT_MENU) && !defined(WIN16) && !(defined(WIN3264) && !defined(FEAT_TEAROFF))
  2898.     if (using_tearoff != prev_tearoff)
  2899.     {
  2900.         gui_mch_toggle_tearoffs(using_tearoff);
  2901.         prev_tearoff = using_tearoff;
  2902.     }
  2903. #endif
  2904.     if (need_set_size)
  2905.         gui_set_shellsize(FALSE, FALSE);
  2906.     }
  2907. }
  2908.  
  2909.  
  2910. /*
  2911.  * Scrollbar stuff:
  2912.  */
  2913.  
  2914.     void
  2915. gui_create_scrollbar(sb, type, wp)
  2916.     scrollbar_T    *sb;
  2917.     int        type;
  2918.     win_T    *wp;
  2919. {
  2920.     static int    sbar_ident = 0;
  2921.  
  2922.     sb->ident = sbar_ident++;    /* No check for too big, but would it happen? */
  2923.     sb->wp = wp;
  2924.     sb->type = type;
  2925.     sb->value = 0;
  2926.     sb->pixval = 0;
  2927.     sb->size = 1;
  2928.     sb->max = 1;
  2929.     sb->top = 0;
  2930.     sb->height = 0;
  2931. #ifdef FEAT_VERTSPLIT
  2932.     sb->width = 0;
  2933. #endif
  2934.     sb->status_height = 0;
  2935.     gui_mch_create_scrollbar(sb, (wp == NULL) ? SBAR_HORIZ : SBAR_VERT);
  2936. }
  2937.  
  2938. /*
  2939.  * Find the scrollbar with the given index.
  2940.  */
  2941.     scrollbar_T *
  2942. gui_find_scrollbar(ident)
  2943.     long    ident;
  2944. {
  2945.     win_T    *wp;
  2946.  
  2947.     if (gui.bottom_sbar.ident == ident)
  2948.     return &gui.bottom_sbar;
  2949.     FOR_ALL_WINDOWS(wp)
  2950.     {
  2951.     if (wp->w_scrollbars[SBAR_LEFT].ident == ident)
  2952.         return &wp->w_scrollbars[SBAR_LEFT];
  2953.     if (wp->w_scrollbars[SBAR_RIGHT].ident == ident)
  2954.         return &wp->w_scrollbars[SBAR_RIGHT];
  2955.     }
  2956.     return NULL;
  2957. }
  2958.  
  2959. /*
  2960.  * For most systems: Put a code in the input buffer for a dragged scrollbar.
  2961.  *
  2962.  * For Win32 and Macintosh:
  2963.  * Scrollbars seem to grab focus and vim doesn't read the input queue until
  2964.  * you stop dragging the scrollbar.  We get here each time the scrollbar is
  2965.  * dragged another pixel, but as far as the rest of vim goes, it thinks
  2966.  * we're just hanging in the call to DispatchMessage() in
  2967.  * process_message().  The DispatchMessage() call that hangs was passed a
  2968.  * mouse button click event in the scrollbar window. -- webb.
  2969.  *
  2970.  * Solution: Do the scrolling right here.  But only when allowed.
  2971.  * Ignore the scrollbars while executing an external command or when there
  2972.  * are still characters to be processed.
  2973.  */
  2974.     void
  2975. gui_drag_scrollbar(sb, value, still_dragging)
  2976.     scrollbar_T    *sb;
  2977.     long    value;
  2978.     int        still_dragging;
  2979. {
  2980. #ifdef FEAT_WINDOWS
  2981.     win_T    *wp;
  2982. #endif
  2983.     int        sb_num;
  2984. #ifdef USE_ON_FLY_SCROLL
  2985.     colnr_T    old_leftcol = curwin->w_leftcol;
  2986.     linenr_T    old_topline = curwin->w_topline;
  2987. # ifdef FEAT_DIFF
  2988.     int        old_topfill = curwin->w_topfill;
  2989. # endif
  2990. #else
  2991.     char_u    bytes[4 + sizeof(long_u)];
  2992.     int        byte_count;
  2993. #endif
  2994.  
  2995.     if (sb == NULL)
  2996.     return;
  2997.  
  2998.     /* Don't put events in the input queue now. */
  2999.     if (hold_gui_events)
  3000.     return;
  3001.  
  3002. #ifdef FEAT_CMDWIN
  3003.     if (cmdwin_type != 0 && sb->wp != curwin)
  3004.     return;
  3005. #endif
  3006.  
  3007.     if (still_dragging)
  3008.     {
  3009.     if (sb->wp == NULL)
  3010.         gui.dragged_sb = SBAR_BOTTOM;
  3011.     else if (sb == &sb->wp->w_scrollbars[SBAR_LEFT])
  3012.         gui.dragged_sb = SBAR_LEFT;
  3013.     else
  3014.         gui.dragged_sb = SBAR_RIGHT;
  3015.     gui.dragged_wp = sb->wp;
  3016.     }
  3017.     else
  3018.     gui.dragged_sb = SBAR_NONE;
  3019.  
  3020.     /* Vertical sbar info is kept in the first sbar (the left one) */
  3021.     if (sb->wp != NULL)
  3022.     sb = &sb->wp->w_scrollbars[0];
  3023.  
  3024.     /*
  3025.      * Check validity of value
  3026.      */
  3027.     if (value < 0)
  3028.     value = 0;
  3029. #ifdef SCROLL_PAST_END
  3030.     else if (value > sb->max)
  3031.     value = sb->max;
  3032. #else
  3033.     if (value > sb->max - sb->size + 1)
  3034.     value = sb->max - sb->size + 1;
  3035. #endif
  3036.  
  3037.     sb->value = value;
  3038.  
  3039. #ifdef USE_ON_FLY_SCROLL
  3040.     /* When not allowed to do the scrolling right now, return. */
  3041.     if (dont_scroll || !vim_is_input_buf_empty())
  3042.     return;
  3043. #endif
  3044.  
  3045. #ifdef FEAT_RIGHTLEFT
  3046.     if (sb->wp == NULL && curwin->w_p_rl)
  3047.     {
  3048.     value = sb->max + 1 - sb->size - value;
  3049.     if (value < 0)
  3050.         value = 0;
  3051.     }
  3052. #endif
  3053.  
  3054.     if (sb->wp != NULL)        /* vertical scrollbar */
  3055.     {
  3056.     sb_num = 0;
  3057. #ifdef FEAT_WINDOWS
  3058.     for (wp = firstwin; wp != sb->wp && wp != NULL; wp = wp->w_next)
  3059.         sb_num++;
  3060.     if (wp == NULL)
  3061.         return;
  3062. #else
  3063.     if (sb->wp != curwin)
  3064.         return;
  3065. #endif
  3066.  
  3067. #ifdef USE_ON_FLY_SCROLL
  3068.     current_scrollbar = sb_num;
  3069.     scrollbar_value = value;
  3070.     if (State & NORMAL)
  3071.     {
  3072.         gui_do_scroll();
  3073.         setcursor();
  3074.     }
  3075.     else if (State & INSERT)
  3076.     {
  3077.         ins_scroll();
  3078.         setcursor();
  3079.     }
  3080.     else if (State & CMDLINE)
  3081.     {
  3082.         if (msg_scrolled == 0)
  3083.         {
  3084.         gui_do_scroll();
  3085.         redrawcmdline();
  3086.         }
  3087.     }
  3088. # ifdef FEAT_FOLDING
  3089.     /* Value may have been changed for closed fold. */
  3090.     sb->value = sb->wp->w_topline - 1;
  3091. # endif
  3092. #else
  3093.     bytes[0] = CSI;
  3094.     bytes[1] = KS_VER_SCROLLBAR;
  3095.     bytes[2] = KE_FILLER;
  3096.     bytes[3] = (char_u)sb_num;
  3097.     byte_count = 4;
  3098. #endif
  3099.     }
  3100.     else
  3101.     {
  3102. #ifdef USE_ON_FLY_SCROLL
  3103.     scrollbar_value = value;
  3104.  
  3105.     if (State & NORMAL)
  3106.         gui_do_horiz_scroll();
  3107.     else if (State & INSERT)
  3108.         ins_horscroll();
  3109.     else if (State & CMDLINE)
  3110.     {
  3111.         if (!msg_scrolled)
  3112.         {
  3113.         gui_do_horiz_scroll();
  3114.         redrawcmdline();
  3115.         }
  3116.     }
  3117.     if (old_leftcol != curwin->w_leftcol)
  3118.     {
  3119.         updateWindow(curwin);   /* update window, status and cmdline */
  3120.         setcursor();
  3121.     }
  3122. #else
  3123.     bytes[0] = CSI;
  3124.     bytes[1] = KS_HOR_SCROLLBAR;
  3125.     bytes[2] = KE_FILLER;
  3126.     byte_count = 3;
  3127. #endif
  3128.     }
  3129.  
  3130. #ifdef USE_ON_FLY_SCROLL
  3131. # ifdef FEAT_SCROLLBIND
  3132.     /*
  3133.      * synchronize other windows, as necessary according to 'scrollbind'
  3134.      */
  3135.     if (curwin->w_p_scb
  3136.         && ((sb->wp == NULL && curwin->w_leftcol != old_leftcol)
  3137.         || (sb->wp == curwin && (curwin->w_topline != old_topline
  3138. #  ifdef FEAT_DIFF
  3139.                        || curwin->w_topfill != old_topfill
  3140. #  endif
  3141.             ))))
  3142.     {
  3143.     do_check_scrollbind(TRUE);
  3144.     /* need to update the window right here */
  3145.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  3146.         if (wp->w_redr_type > 0)
  3147.         updateWindow(wp);
  3148.     setcursor();
  3149.     }
  3150. # endif
  3151.     out_flush();
  3152.     gui_update_cursor(FALSE, TRUE);
  3153. #else
  3154.     add_long_to_buf((long)value, bytes + byte_count);
  3155.     add_to_input_buf(bytes, byte_count + sizeof(long_u));
  3156. #endif
  3157. }
  3158.  
  3159. /*
  3160.  * Scrollbar stuff:
  3161.  */
  3162.  
  3163.     void
  3164. gui_update_scrollbars(force)
  3165.     int        force;        /* Force all scrollbars to get updated */
  3166. {
  3167.     win_T    *wp;
  3168.     scrollbar_T    *sb;
  3169.     long    val, size, max;        /* need 32 bits here */
  3170.     int        which_sb;
  3171.     int        h, y;
  3172. #ifdef FEAT_VERTSPLIT
  3173.     static win_T *prev_curwin = NULL;
  3174. #endif
  3175.  
  3176.     /* Update the horizontal scrollbar */
  3177.     gui_update_horiz_scrollbar(force);
  3178.  
  3179. #ifndef WIN3264
  3180.     /* Return straight away if there is neither a left nor right scrollbar.
  3181.      * On MS-Windows this is required anyway for scrollwheel messages. */
  3182.     if (!gui.which_scrollbars[SBAR_LEFT] && !gui.which_scrollbars[SBAR_RIGHT])
  3183.     return;
  3184. #endif
  3185.  
  3186.     /*
  3187.      * Don't want to update a scrollbar while we're dragging it.  But if we
  3188.      * have both a left and right scrollbar, and we drag one of them, we still
  3189.      * need to update the other one.
  3190.      */
  3191.     if (       (gui.dragged_sb == SBAR_LEFT
  3192.         || gui.dragged_sb == SBAR_RIGHT)
  3193.         && (!gui.which_scrollbars[SBAR_LEFT]
  3194.         || !gui.which_scrollbars[SBAR_RIGHT])
  3195.         && !force)
  3196.     return;
  3197.  
  3198.     if (!force && (gui.dragged_sb == SBAR_LEFT || gui.dragged_sb == SBAR_RIGHT))
  3199.     {
  3200.     /*
  3201.      * If we have two scrollbars and one of them is being dragged, just
  3202.      * copy the scrollbar position from the dragged one to the other one.
  3203.      */
  3204.     which_sb = SBAR_LEFT + SBAR_RIGHT - gui.dragged_sb;
  3205.     if (gui.dragged_wp != NULL)
  3206.         gui_mch_set_scrollbar_thumb(
  3207.             &gui.dragged_wp->w_scrollbars[which_sb],
  3208.             gui.dragged_wp->w_scrollbars[0].value,
  3209.             gui.dragged_wp->w_scrollbars[0].size,
  3210.             gui.dragged_wp->w_scrollbars[0].max);
  3211.     return;
  3212.     }
  3213.  
  3214.     /* avoid that moving components around generates events */
  3215.     ++hold_gui_events;
  3216.  
  3217.     for (wp = firstwin; wp != NULL; wp = W_NEXT(wp))
  3218.     {
  3219.     if (wp->w_buffer == NULL)    /* just in case */
  3220.         continue;
  3221. #ifdef SCROLL_PAST_END
  3222.     max = wp->w_buffer->b_ml.ml_line_count - 1;
  3223. #else
  3224.     max = wp->w_buffer->b_ml.ml_line_count + wp->w_height - 2;
  3225. #endif
  3226.     if (max < 0)            /* empty buffer */
  3227.         max = 0;
  3228.     val = wp->w_topline - 1;
  3229.     size = wp->w_height;
  3230. #ifdef SCROLL_PAST_END
  3231.     if (val > max)            /* just in case */
  3232.         val = max;
  3233. #else
  3234.     if (size > max + 1)        /* just in case */
  3235.         size = max + 1;
  3236.     if (val > max - size + 1)
  3237.         val = max - size + 1;
  3238. #endif
  3239.     if (val < 0)            /* minimal value is 0 */
  3240.         val = 0;
  3241.  
  3242.     /*
  3243.      * Scrollbar at index 0 (the left one) contains all the information.
  3244.      * It would be the same info for left and right so we just store it for
  3245.      * one of them.
  3246.      */
  3247.     sb = &wp->w_scrollbars[0];
  3248.  
  3249.     /*
  3250.      * Note: no check for valid w_botline.    If it's not valid the
  3251.      * scrollbars will be updated later anyway.
  3252.      */
  3253.     if (size < 1 || wp->w_botline - 2 > max)
  3254.     {
  3255.         /*
  3256.          * This can happen during changing files.  Just don't update the
  3257.          * scrollbar for now.
  3258.          */
  3259.         sb->height = 0;        /* Force update next time */
  3260.         if (gui.which_scrollbars[SBAR_LEFT])
  3261.         gui_do_scrollbar(wp, SBAR_LEFT, FALSE);
  3262.         if (gui.which_scrollbars[SBAR_RIGHT])
  3263.         gui_do_scrollbar(wp, SBAR_RIGHT, FALSE);
  3264.         continue;
  3265.     }
  3266.     if (force || sb->height != wp->w_height
  3267. #ifdef FEAT_WINDOWS
  3268.         || sb->top != wp->w_winrow
  3269.         || sb->status_height != wp->w_status_height
  3270. # ifdef FEAT_VERTSPLIT
  3271.         || sb->width != wp->w_width
  3272.         || prev_curwin != curwin
  3273. # endif
  3274. #endif
  3275.         )
  3276.     {
  3277.         /* Height, width or position of scrollbar has changed.  For
  3278.          * vertical split: curwin changed. */
  3279.         sb->height = wp->w_height;
  3280. #ifdef FEAT_WINDOWS
  3281.         sb->top = wp->w_winrow;
  3282.         sb->status_height = wp->w_status_height;
  3283. # ifdef FEAT_VERTSPLIT
  3284.         sb->width = wp->w_width;
  3285. # endif
  3286. #endif
  3287.  
  3288.         /* Calculate height and position in pixels */
  3289.         h = (sb->height + sb->status_height) * gui.char_height;
  3290.         y = sb->top * gui.char_height + gui.border_offset;
  3291. #if defined(FEAT_MENU) && !defined(FEAT_GUI_GTK) && !defined(FEAT_GUI_MOTIF) && !defined(FEAT_GUI_PHOTON)
  3292.         if (gui.menu_is_active)
  3293.         y += gui.menu_height;
  3294. #endif
  3295.  
  3296. #if defined(FEAT_TOOLBAR) && (defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_ATHENA))
  3297.         if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
  3298. # ifdef FEAT_GUI_ATHENA
  3299.         y += gui.toolbar_height;
  3300. # else
  3301. #  ifdef FEAT_GUI_MSWIN
  3302.         y += TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT;
  3303. #  endif
  3304. # endif
  3305. #endif
  3306.  
  3307. #ifdef FEAT_WINDOWS
  3308.         if (wp->w_winrow == 0)
  3309. #endif
  3310.         {
  3311.         /* Height of top scrollbar includes width of top border */
  3312.         h += gui.border_offset;
  3313.         y -= gui.border_offset;
  3314.         }
  3315.         if (gui.which_scrollbars[SBAR_LEFT])
  3316.         {
  3317.         gui_mch_set_scrollbar_pos(&wp->w_scrollbars[SBAR_LEFT],
  3318.                       gui.left_sbar_x, y,
  3319.                       gui.scrollbar_width, h);
  3320.         gui_do_scrollbar(wp, SBAR_LEFT, TRUE);
  3321.         }
  3322.         if (gui.which_scrollbars[SBAR_RIGHT])
  3323.         {
  3324.         gui_mch_set_scrollbar_pos(&wp->w_scrollbars[SBAR_RIGHT],
  3325.                       gui.right_sbar_x, y,
  3326.                       gui.scrollbar_width, h);
  3327.         gui_do_scrollbar(wp, SBAR_RIGHT, TRUE);
  3328.         }
  3329.     }
  3330.  
  3331.     /* reduce the number of calls to gui_mch_set_scrollbar_thumb() by
  3332.      * checking if the thumb moved at least a pixel */
  3333.     if (max == 0)
  3334.         y = 0;
  3335.     else
  3336.         y = (val * (sb->height + 2) * gui.char_height + max / 2) / max;
  3337. #ifndef RISCOS
  3338.     /* RISCOS does scrollbars differently - if the position through the
  3339.      * file has changed then we must update the scrollbar regardless of
  3340.      * how far we think it has moved. */
  3341.     if (force || sb->pixval != y || sb->size != size || sb->max != max)
  3342. #endif
  3343.     {
  3344.         /* Thumb of scrollbar has moved */
  3345.         sb->value = val;
  3346.         sb->pixval = y;
  3347.         sb->size = size;
  3348.         sb->max = max;
  3349.         if (gui.which_scrollbars[SBAR_LEFT] && gui.dragged_sb != SBAR_LEFT)
  3350.         gui_mch_set_scrollbar_thumb(&wp->w_scrollbars[SBAR_LEFT],
  3351.                         val, size, max);
  3352.         if (gui.which_scrollbars[SBAR_RIGHT]
  3353.                     && gui.dragged_sb != SBAR_RIGHT)
  3354.         gui_mch_set_scrollbar_thumb(&wp->w_scrollbars[SBAR_RIGHT],
  3355.                         val, size, max);
  3356.     }
  3357.     }
  3358. #ifdef FEAT_VERTSPLIT
  3359.     prev_curwin = curwin;
  3360. #endif
  3361.     --hold_gui_events;
  3362. }
  3363.  
  3364. /*
  3365.  * Enable or disable a scrollbar.
  3366.  * Check for scrollbars for vertically split windows which are not enabled
  3367.  * sometimes.
  3368.  */
  3369.     static void
  3370. gui_do_scrollbar(wp, which, enable)
  3371.     win_T    *wp;
  3372.     int        which;        /* SBAR_LEFT or SBAR_RIGHT */
  3373.     int        enable;        /* TRUE to enable scrollbar */
  3374. {
  3375. #ifdef FEAT_VERTSPLIT
  3376.     int        midcol = curwin->w_wincol + curwin->w_width / 2;
  3377.     int        has_midcol = (wp->w_wincol <= midcol
  3378.                      && wp->w_wincol + wp->w_width >= midcol);
  3379.  
  3380.     /* Only enable scrollbars that contain the middle column of the current
  3381.      * window. */
  3382.     if (gui.which_scrollbars[SBAR_RIGHT] != gui.which_scrollbars[SBAR_LEFT])
  3383.     {
  3384.     /* Scrollbars only on one side.  Don't enable scrollbars that don't
  3385.      * contain the middle column of the current window. */
  3386.     if (!has_midcol)
  3387.         enable = FALSE;
  3388.     }
  3389.     else
  3390.     {
  3391.     /* Scrollbars on both sides.  Don't enable scrollbars that neither
  3392.      * contain the middle column of the current window nor are on the far
  3393.      * side. */
  3394.     if (midcol > Columns / 2)
  3395.     {
  3396.         if (which == SBAR_LEFT ? wp->w_wincol != 0 : !has_midcol)
  3397.         enable = FALSE;
  3398.     }
  3399.     else
  3400.     {
  3401.         if (which == SBAR_RIGHT ? wp->w_wincol + wp->w_width != Columns
  3402.                                 : !has_midcol)
  3403.         enable = FALSE;
  3404.     }
  3405.     }
  3406. #endif
  3407.     gui_mch_enable_scrollbar(&wp->w_scrollbars[which], enable);
  3408. }
  3409.  
  3410. /*
  3411.  * Scroll a window according to the values set in the globals current_scrollbar
  3412.  * and scrollbar_value.  Return TRUE if the cursor in the current window moved
  3413.  * or FALSE otherwise.
  3414.  */
  3415.     int
  3416. gui_do_scroll()
  3417. {
  3418.     win_T    *wp, *save_wp;
  3419.     int        i;
  3420.     long    nlines;
  3421.     pos_T    old_cursor;
  3422.     linenr_T    old_topline;
  3423. #ifdef FEAT_DIFF
  3424.     int        old_topfill;
  3425. #endif
  3426.  
  3427.     for (wp = firstwin, i = 0; i < current_scrollbar; wp = W_NEXT(wp), i++)
  3428.     if (wp == NULL)
  3429.         break;
  3430.     if (wp == NULL)
  3431.     /* Couldn't find window */
  3432.     return FALSE;
  3433.  
  3434.     /*
  3435.      * Compute number of lines to scroll.  If zero, nothing to do.
  3436.      */
  3437.     nlines = (long)scrollbar_value + 1 - (long)wp->w_topline;
  3438.     if (nlines == 0)
  3439.     return FALSE;
  3440.  
  3441.     save_wp = curwin;
  3442.     old_topline = wp->w_topline;
  3443. #ifdef FEAT_DIFF
  3444.     old_topfill = wp->w_topfill;
  3445. #endif
  3446.     old_cursor = wp->w_cursor;
  3447.     curwin = wp;
  3448.     curbuf = wp->w_buffer;
  3449.     if (nlines < 0)
  3450.     scrolldown(-nlines, gui.dragged_wp == NULL);
  3451.     else
  3452.     scrollup(nlines, gui.dragged_wp == NULL);
  3453.     /* Reset dragged_wp after using it.  "dragged_sb" will have been reset for
  3454.      * the mouse-up event already, but we still want it to behave like when
  3455.      * dragging.  But not the next click in an arrow. */
  3456.     if (gui.dragged_sb == SBAR_NONE)
  3457.     gui.dragged_wp = NULL;
  3458.  
  3459.     if (old_topline != wp->w_topline
  3460. #ifdef FEAT_DIFF
  3461.         || old_topfill != wp->w_topfill
  3462. #endif
  3463.         )
  3464.     {
  3465.     if (p_so != 0)
  3466.     {
  3467.         cursor_correct();        /* fix window for 'so' */
  3468.         update_topline();        /* avoid up/down jump */
  3469.     }
  3470.     if (old_cursor.lnum != wp->w_cursor.lnum)
  3471.         coladvance(wp->w_curswant);
  3472. #ifdef FEAT_SCROLLBIND
  3473.     wp->w_scbind_pos = wp->w_topline;
  3474. #endif
  3475.     }
  3476.  
  3477.     curwin = save_wp;
  3478.     curbuf = save_wp->w_buffer;
  3479.  
  3480.     /*
  3481.      * Don't call updateWindow() when nothing has changed (it will overwrite
  3482.      * the status line!).
  3483.      */
  3484.     if (old_topline != wp->w_topline
  3485. #ifdef FEAT_DIFF
  3486.         || old_topfill != wp->w_topfill
  3487. #endif
  3488.         )
  3489.     {
  3490.     redraw_win_later(wp, VALID);
  3491.     updateWindow(wp);   /* update window, status line, and cmdline */
  3492.     }
  3493.  
  3494.     return (wp == curwin && !equal(curwin->w_cursor, old_cursor));
  3495. }
  3496.  
  3497.  
  3498. /*
  3499.  * Horizontal scrollbar stuff:
  3500.  */
  3501.  
  3502.     static void
  3503. gui_update_horiz_scrollbar(force)
  3504.     int        force;
  3505. {
  3506.     long    value, size, max;    /* need 32 bit ints here */
  3507.     char_u    *p;
  3508.  
  3509.     if (!gui.which_scrollbars[SBAR_BOTTOM])
  3510.     return;
  3511.  
  3512.     if (!force && gui.dragged_sb == SBAR_BOTTOM)
  3513.     return;
  3514.  
  3515.     if (!force && curwin->w_p_wrap && gui.prev_wrap)
  3516.     return;
  3517.  
  3518.     /*
  3519.      * It is possible for the cursor to be invalid if we're in the middle of
  3520.      * something (like changing files).  If so, don't do anything for now.
  3521.      */
  3522.     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  3523.     {
  3524.     gui.bottom_sbar.value = -1;
  3525.     return;
  3526.     }
  3527.  
  3528.     size = W_WIDTH(curwin);
  3529.     if (curwin->w_p_wrap)
  3530.     {
  3531.     value = 0;
  3532. #ifdef SCROLL_PAST_END
  3533.     max = 0;
  3534. #else
  3535.     max = W_WIDTH(curwin) - 1;
  3536. #endif
  3537.     }
  3538.     else
  3539.     {
  3540.     value = curwin->w_leftcol;
  3541.  
  3542.     /* Calculate max for horizontal scrollbar */
  3543.     p = ml_get_curline();
  3544.     max = 0;
  3545.     if (p != NULL && p[0] != NUL)
  3546.         for (;;)
  3547.         {
  3548.         int w = chartabsize(p, (colnr_T)max);
  3549. #ifdef FEAT_MBYTE
  3550.         if (has_mbyte)
  3551.             p += (*mb_ptr2len_check)(p);
  3552.         else
  3553. #endif
  3554.             ++p;
  3555.         if (*p == NUL)        /* Don't count last character */
  3556.             break;
  3557.         max += w;
  3558.         }
  3559. #ifndef SCROLL_PAST_END
  3560.     max += W_WIDTH(curwin) - 1;
  3561. #endif
  3562.     /* The line number isn't scrolled, thus there is less space when
  3563.      * 'number' is set (also for 'foldcolumn'). */
  3564.     size -= curwin_col_off();
  3565. #ifndef SCROLL_PAST_END
  3566.     max -= curwin_col_off();
  3567. #endif
  3568.     }
  3569.  
  3570. #ifndef SCROLL_PAST_END
  3571.     if (value > max - size + 1)
  3572.     value = max - size + 1;        /* limit the value to allowable range */
  3573. #endif
  3574.  
  3575. #ifdef FEAT_RIGHTLEFT
  3576.     if (curwin->w_p_rl)
  3577.     {
  3578.     value = max + 1 - size - value;
  3579.     if (value < 0)
  3580.     {
  3581.         size += value;
  3582.         value = 0;
  3583.     }
  3584.     }
  3585. #endif
  3586.     if (!force && value == gui.bottom_sbar.value && size == gui.bottom_sbar.size
  3587.                         && max == gui.bottom_sbar.max)
  3588.     return;
  3589.  
  3590.     gui.bottom_sbar.value = value;
  3591.     gui.bottom_sbar.size = size;
  3592.     gui.bottom_sbar.max = max;
  3593.     gui.prev_wrap = curwin->w_p_wrap;
  3594.  
  3595.     gui_mch_set_scrollbar_thumb(&gui.bottom_sbar, value, size, max);
  3596. }
  3597.  
  3598. /*
  3599.  * Do a horizontal scroll.  Return TRUE if the cursor moved, FALSE otherwise.
  3600.  */
  3601.     int
  3602. gui_do_horiz_scroll()
  3603. {
  3604.     /* no wrapping, no scrolling */
  3605.     if (curwin->w_p_wrap)
  3606.     return FALSE;
  3607.  
  3608.     if (curwin->w_leftcol == scrollbar_value)
  3609.     return FALSE;
  3610.  
  3611.     curwin->w_leftcol = scrollbar_value;
  3612.     return leftcol_changed();
  3613. }
  3614.  
  3615. /*
  3616.  * Check that none of the colors are the same as the background color
  3617.  */
  3618.     void
  3619. gui_check_colors()
  3620. {
  3621.     if (gui.norm_pixel == gui.back_pixel || gui.norm_pixel == (guicolor_T)-1)
  3622.     {
  3623.     gui_set_bg_color((char_u *)"White");
  3624.     if (gui.norm_pixel == gui.back_pixel || gui.norm_pixel == (guicolor_T)-1)
  3625.         gui_set_fg_color((char_u *)"Black");
  3626.     }
  3627. }
  3628.  
  3629.     void
  3630. gui_set_fg_color(name)
  3631.     char_u    *name;
  3632. {
  3633.     gui.norm_pixel = gui_mch_get_color(name);
  3634.     hl_set_fg_color_name(vim_strsave(name));
  3635. }
  3636.  
  3637.     void
  3638. gui_set_bg_color(name)
  3639.     char_u    *name;
  3640. {
  3641.     gui.back_pixel = gui_mch_get_color(name);
  3642.     hl_set_bg_color_name(vim_strsave(name));
  3643. }
  3644.  
  3645. /*
  3646.  * Return the grey value of a color (range 0-255).
  3647.  */
  3648.     int
  3649. gui_get_lightness(pixel)
  3650.     guicolor_T    pixel;
  3651. {
  3652.     long_u    rgb = gui_mch_get_rgb(pixel);
  3653.  
  3654.     return (  (((rgb >> 16) & 0xff) * 299)
  3655.         + (((rgb >> 8)  & 0xff) * 587)
  3656.         +  ((rgb        & 0xff) * 114)) / 1000;
  3657. }
  3658.  
  3659. #if defined(FEAT_GUI_X11) || defined(PROTO)
  3660.     void
  3661. gui_new_scrollbar_colors()
  3662. {
  3663.     win_T    *wp;
  3664.  
  3665.     /* Nothing to do if GUI hasn't started yet. */
  3666.     if (!gui.in_use)
  3667.     return;
  3668.  
  3669.     FOR_ALL_WINDOWS(wp)
  3670.     {
  3671.     gui_mch_set_scrollbar_colors(&(wp->w_scrollbars[SBAR_LEFT]));
  3672.     gui_mch_set_scrollbar_colors(&(wp->w_scrollbars[SBAR_RIGHT]));
  3673.     }
  3674.     gui_mch_set_scrollbar_colors(&gui.bottom_sbar);
  3675. }
  3676. #endif
  3677.  
  3678. /*
  3679.  * Call this when focus has changed.
  3680.  */
  3681.     void
  3682. gui_focus_change(in_focus)
  3683.     int        in_focus;
  3684. {
  3685.     gui.in_focus = in_focus;
  3686.     out_flush();        /* make sure output has been written */
  3687.     gui_update_cursor(TRUE, FALSE);
  3688.  
  3689. #ifdef FEAT_XIM
  3690.     xim_set_focus(in_focus);
  3691. #endif
  3692.  
  3693.     ui_focus_change(in_focus);
  3694. }
  3695.  
  3696. /*
  3697.  * Called when the mouse moved (but not when dragging).
  3698.  */
  3699.     void
  3700. gui_mouse_moved(x, y)
  3701.     int        x;
  3702.     int        y;
  3703. {
  3704.     win_T    *wp;
  3705.     char_u    st[6];
  3706.  
  3707. #ifdef FEAT_MOUSESHAPE
  3708.     /* Get window pointer, and update mouse shape as well. */
  3709.     wp = xy2win(x, y);
  3710. #endif
  3711.  
  3712.     /* Only handle this when 'mousefocus' set and ... */
  3713.     if (p_mousef
  3714.         && !hold_gui_events        /* not holding events */
  3715.         && (State & (NORMAL|INSERT))/* Normal/Visual/Insert mode */
  3716.         && State != HITRETURN    /* but not hit-return prompt */
  3717.         && msg_scrolled == 0    /* no scrolled message */
  3718.         && !need_mouse_correct    /* not moving the pointer */
  3719.         && gui.in_focus)        /* gvim in focus */
  3720.     {
  3721.     /* Don't move the mouse when it's left or right of the Vim window */
  3722.     if (x < 0 || x > Columns * gui.char_width)
  3723.         return;
  3724. #ifndef FEAT_MOUSESHAPE
  3725.     wp = xy2win(x, y);
  3726. #endif
  3727.     if (wp == curwin || wp == NULL)
  3728.         return;    /* still in the same old window, or none at all */
  3729.  
  3730.     /*
  3731.      * format a mouse click on status line input
  3732.      * ala gui_send_mouse_event(0, x, y, 0, 0);
  3733.      * Trick: Use a column of -1, so that check_termcode will generate a
  3734.      * K_LEFTMOUSE_NM key code.
  3735.      */
  3736.     if (finish_op)
  3737.     {
  3738.         /* abort the current operator first */
  3739.         st[0] = ESC;
  3740.         add_to_input_buf(st, 1);
  3741.     }
  3742.     st[0] = CSI;
  3743.     st[1] = KS_MOUSE;
  3744.     st[2] = KE_FILLER;
  3745.     st[3] = (char_u)MOUSE_LEFT;
  3746. #ifdef FEAT_VERTSPLIT
  3747.     st[4] = (char_u)(W_WINCOL(wp) + ' ' + 1);    /* column -1 */
  3748. #else
  3749.     st[4] = (char_u)(' ');        /* column -1 */
  3750. #endif
  3751.     st[5] = (char_u)(wp->w_height + W_WINROW(wp) + ' ' + 1);
  3752.     add_to_input_buf(st, 6);
  3753.     st[3] = (char_u)MOUSE_RELEASE;
  3754.     add_to_input_buf(st, 6);
  3755.  
  3756. #ifdef FEAT_GUI_GTK
  3757.     /* Need to wake up the main loop */
  3758.     if (gtk_main_level() > 0)
  3759.         gtk_main_quit();
  3760. #endif
  3761.     }
  3762. }
  3763.  
  3764. /*
  3765.  * Called when mouse should be moved to window with focus.
  3766.  */
  3767.     void
  3768. gui_mouse_correct()
  3769. {
  3770.     int        x, y;
  3771.     win_T    *wp = NULL;
  3772.  
  3773.     need_mouse_correct = FALSE;
  3774.     if (gui.in_use && p_mousef)
  3775.     {
  3776.     x = gui_mch_get_mouse_x();
  3777.     /* Don't move the mouse when it's left or right of the Vim window */
  3778.     if (x < 0 || x > Columns * gui.char_width)
  3779.         return;
  3780.     y = gui_mch_get_mouse_y();
  3781.     if (y >= 0)
  3782.         wp = xy2win(x, y);
  3783.     if (wp != curwin && wp != NULL)    /* If in other than current window */
  3784.     {
  3785.         validate_cline_row();
  3786.         gui_mch_setmouse((int)W_ENDCOL(curwin) * gui.char_width - 3,
  3787.              (W_WINROW(curwin) + curwin->w_wrow) * gui.char_height
  3788.                              + (gui.char_height) / 2);
  3789.     }
  3790.     }
  3791. }
  3792.  
  3793. /*
  3794.  * Find window where the mouse pointer "y" coordinate is in.
  3795.  */
  3796. /*ARGSUSED*/
  3797.     static win_T *
  3798. xy2win(x, y)
  3799.     int        x;
  3800.     int        y;
  3801. {
  3802. #ifdef FEAT_WINDOWS
  3803.     int        row;
  3804.     int        col;
  3805.     win_T    *wp;
  3806.  
  3807.     row = Y_2_ROW(y);
  3808.     col = X_2_COL(x);
  3809.     if (row < 0 || col < 0)        /* before first window */
  3810.     return NULL;
  3811.     wp = mouse_find_win(&row, &col);
  3812. # ifdef FEAT_MOUSESHAPE
  3813.     if (State == HITRETURN || State == ASKMORE)
  3814.     update_mouseshape(SHAPE_IDX_MORE);
  3815.     else if (row > wp->w_height)    /* below status line */
  3816.     update_mouseshape(SHAPE_IDX_CLINE);
  3817. #  ifdef FEAT_VERTSPLIT
  3818.     else if (!(State & CMDLINE) && W_VSEP_WIDTH(wp) > 0 && col == wp->w_width
  3819.         && (row != wp->w_height || !stl_connected(wp)))
  3820.     update_mouseshape(SHAPE_IDX_VSEP);
  3821. #  endif
  3822.     else if (!(State & CMDLINE) && W_STATUS_HEIGHT(wp) > 0
  3823.                                && row == wp->w_height)
  3824.     update_mouseshape(SHAPE_IDX_STATUS);
  3825.     else
  3826.     update_mouseshape(-2);
  3827. # endif
  3828.     return wp;
  3829. #else
  3830.     return firstwin;
  3831. #endif
  3832. }
  3833.  
  3834. /*
  3835.  * ":gui" and ":gvim": Change from the terminal version to the GUI version.
  3836.  * File names may be given to redefine the args list.
  3837.  */
  3838.     void
  3839. ex_gui(eap)
  3840.     exarg_T    *eap;
  3841. {
  3842.     char_u    *arg = eap->arg;
  3843.  
  3844.     /*
  3845.      * Check for "-f" argument: foreground, don't fork.
  3846.      * Also don't fork when started with "gvim -f".
  3847.      * Do fork when using "gui -b".
  3848.      */
  3849.     if (arg[0] == '-'
  3850.         && (arg[1] == 'f' || arg[1] == 'b')
  3851.         && (arg[2] == NUL || vim_iswhite(arg[2])))
  3852.     {
  3853.     gui.dofork = (arg[1] == 'b');
  3854.     eap->arg = skipwhite(eap->arg + 2);
  3855.     }
  3856.     if (!gui.in_use)
  3857.     {
  3858.     /* Clear the command.  Needed for when forking+exiting, to avoid part
  3859.      * of the argument ending up after the shell prompt. */
  3860.     msg_clr_eos();
  3861.     gui_start();
  3862.     }
  3863.     if (!ends_excmd(*eap->arg))
  3864.     ex_next(eap);
  3865. }
  3866.  
  3867. #if ((defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_W32) \
  3868.     || defined(FEAT_GUI_PHOTON)) && defined(FEAT_TOOLBAR)) || defined(PROTO)
  3869. /*
  3870.  * This is shared between Athena, Motif and GTK.
  3871.  */
  3872. static char_u    *gfp_buffer;
  3873.  
  3874. static void gfp_setname __ARGS((char_u *fname));
  3875.  
  3876. /*
  3877.  * Callback function for do_in_runtimepath().
  3878.  */
  3879.     static void
  3880. gfp_setname(fname)
  3881.     char_u    *fname;
  3882. {
  3883.     if (STRLEN(fname) >= MAXPATHL)
  3884.     *gfp_buffer = NUL;
  3885.     else
  3886.     STRCPY(gfp_buffer, fname);
  3887. }
  3888.  
  3889. /*
  3890.  * Find the path of bitmap "name" with extension "ext" in 'runtimepath'.
  3891.  * Return FAIL for failure and OK if buffer[MAXPATHL] contains the result.
  3892.  */
  3893.     int
  3894. gui_find_bitmap(name, buffer, ext)
  3895.     char_u    *name;
  3896.     char_u    *buffer;
  3897.     char    *ext;
  3898. {
  3899.     if (STRLEN(name) > MAXPATHL - 14)
  3900.     return FAIL;
  3901.     sprintf((char *)buffer, "bitmaps/%s.%s", name, ext);
  3902.     gfp_buffer = buffer;
  3903.     if (do_in_runtimepath(buffer, FALSE, gfp_setname) == FAIL || *buffer == NUL)
  3904.     return FAIL;
  3905.     return OK;
  3906. }
  3907. #endif
  3908.  
  3909. #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) || defined(PROTO)
  3910.     void
  3911. display_errors()
  3912. {
  3913.     char_u    *p;
  3914.  
  3915.     if (isatty(2))
  3916.     fflush(stderr);
  3917.     else if (error_ga.ga_data != NULL)
  3918.     {
  3919.     /* avoid putting up a message box with blanks only */
  3920.     for (p = (char_u *)error_ga.ga_data; *p != NUL; ++p)
  3921.         if (!isspace(*p))
  3922.         {
  3923.         /* Truncate a very long message, it will go off-screen. */
  3924.         if (STRLEN(p) > 2000)
  3925.             STRCPY(p + 2000 - 14, "...(truncated)");
  3926.         (void)do_dialog(VIM_ERROR, (char_u *)_("Error"),
  3927.                           p, (char_u *)_("&Ok"), 1, NULL);
  3928.         break;
  3929.         }
  3930.     ga_clear(&error_ga);
  3931.     }
  3932. }
  3933. #endif
  3934.  
  3935. #if defined(NO_CONSOLE_INPUT) || defined(PROTO)
  3936. /*
  3937.  * Return TRUE if still starting up and there is no place to enter text.
  3938.  * For GTK and X11 we check if stderr is not a tty, which means we were
  3939.  * (probably) started from the desktop.  Also check stdin, "vim >& file" does
  3940.  * allow typing on stdin.
  3941.  */
  3942.     int
  3943. no_console_input()
  3944. {
  3945.     return ((!gui.in_use || gui.starting)
  3946. # ifndef NO_CONSOLE
  3947.         && !isatty(0) && !isatty(2)
  3948. # endif
  3949.         );
  3950. }
  3951. #endif
  3952.  
  3953. #if defined(FEAT_SUN_WORKSHOP) || defined(FEAT_GUI_MOTIF) || defined(PROTO)
  3954. /*
  3955.  * Update the current window and the screen.
  3956.  */
  3957.     void
  3958. gui_update_screen()
  3959. {
  3960.     update_topline();
  3961.     validate_cursor();
  3962.     update_screen(0);    /* may need to update the screen */
  3963.     setcursor();
  3964.     out_flush();        /* make sure output has been written */
  3965.     gui_update_cursor(TRUE, FALSE);
  3966.     gui_mch_flush();
  3967. }
  3968. #endif
  3969.  
  3970. #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_MOTIF) || defined(PROTO)
  3971. /*
  3972.  * Get the text to use in a find/replace dialog.  Uses the last search pattern
  3973.  * if the argument is empty.
  3974.  * Returns an allocated string.
  3975.  */
  3976.     char_u *
  3977. get_find_dialog_text(arg, wordp)
  3978.     char_u    *arg;
  3979.     int        *wordp;        /* return: TRUE if \< \> found */
  3980. {
  3981.     char_u    *text;
  3982.  
  3983.     if (*arg == NUL)
  3984.     text = last_search_pat();
  3985.     else
  3986.     text = arg;
  3987.     if (text != NULL)
  3988.     {
  3989.     text = vim_strsave(text);
  3990.     if (text != NULL)
  3991.     {
  3992.         int len = STRLEN(text);
  3993.  
  3994.         /* Remove "\V" */
  3995.         if (len >= 2 && STRNCMP(text, "\\V", 2) == 0)
  3996.         mch_memmove(text, text + 2, (size_t)(len - 2));
  3997.  
  3998.         /* Recognize "\<text\>" and remove. */
  3999.         if (len >= 4
  4000.             && STRNCMP(text, "\\<", 2) == 0
  4001.             && STRNCMP(text + len - 2, "\\>", 2) == 0)
  4002.         {
  4003.         *wordp = TRUE;
  4004.         mch_memmove(text, text + 2, (size_t)(len - 4));
  4005.         text[len - 4] = NUL;
  4006.         }
  4007.     }
  4008.     }
  4009.     return text;
  4010. }
  4011.  
  4012. /*
  4013.  * Handle the press of a button in the find-replace dialog.
  4014.  * Return TRUE when something was added to the input buffer.
  4015.  */
  4016.     int
  4017. gui_do_findrepl(flags, find_text, repl_text, down, exact)
  4018.     int        flags;        /* one of FR_REPLACE, FR_FINDNEXT, etc. */
  4019.     char_u    *find_text;
  4020.     char_u    *repl_text;
  4021.     int        down;        /* Search downwards. */
  4022.     int        exact;        /* Exact word match. */
  4023. {
  4024.     garray_T    ga;
  4025.  
  4026.     ga_init2(&ga, 1, 100);
  4027.  
  4028.     /* start stuffing in the command text */
  4029.     if (State & INSERT)
  4030.     ga_append(&ga, Ctrl_O);
  4031.     else if ((State | NORMAL) == 0)
  4032.     ga_append(&ga, ESC);
  4033.  
  4034.     if (flags == FR_REPLACE)
  4035.     {
  4036.     /* Do the replacement when the text under the cursor matches. */
  4037.     if (STRNCMP(ml_get_cursor(), find_text, STRLEN(find_text)) == 0
  4038.         && u_save_cursor() == OK)
  4039.     {
  4040.         del_bytes((long)STRLEN(find_text), FALSE);
  4041.         ins_str(repl_text);
  4042.     }
  4043.     }
  4044.     else if (flags == FR_REPLACEALL)
  4045.     {
  4046.     ga_concat(&ga, (char_u *)":%sno/");
  4047.     ga_concat(&ga, find_text);
  4048.     ga_concat(&ga, (char_u *)"/");
  4049.     ga_concat(&ga, repl_text);
  4050.     ga_concat(&ga, (char_u *)"/g\r");
  4051.     }
  4052.  
  4053.     if (flags != FR_REPLACEALL)
  4054.     {
  4055.     /* Search for the next match. */
  4056.     if (down)
  4057.         ga_concat(&ga, (char_u *)"/\\V");
  4058.     else
  4059.         ga_concat(&ga, (char_u *)"?\\V");
  4060.     if (exact)
  4061.         ga_concat(&ga, (char_u *)"\\<");
  4062.     ga_concat(&ga, find_text);
  4063.     if (exact)
  4064.         ga_concat(&ga, (char_u *)"\\>");
  4065.     ga_concat(&ga, (char_u *)"\r");
  4066.     }
  4067.  
  4068.     if (ga.ga_len > 0)
  4069.     add_to_input_buf((char_u *)ga.ga_data, ga.ga_len);
  4070.  
  4071.     vim_free(ga.ga_data);
  4072.     return (ga.ga_len > 0);
  4073. }
  4074.  
  4075. #endif
  4076.